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_av1.h"
26 #include "util/u_video.h"
27 #include "d3d12_resource.h"
28 #include "d3d12_screen.h"
29 #include "d3d12_format.h"
30 #include <cmath>
31 #include <numeric>
32
33 void
d3d12_video_encoder_update_current_rate_control_av1(struct d3d12_video_encoder * pD3D12Enc,pipe_av1_enc_picture_desc * picture)34 d3d12_video_encoder_update_current_rate_control_av1(struct d3d12_video_encoder *pD3D12Enc,
35 pipe_av1_enc_picture_desc *picture)
36 {
37 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc = {};
38 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_FrameRate.Numerator = picture->rc[0].frame_rate_num;
39 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_FrameRate.Denominator = picture->rc[0].frame_rate_den;
40 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags = D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_NONE;
41
42 if (picture->roi.num > 0)
43 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
44 D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_DELTA_QP;
45
46 switch (picture->rc[0].rate_ctrl_method) {
47 case PIPE_H2645_ENC_RATE_CONTROL_METHOD_VARIABLE_SKIP:
48 case PIPE_H2645_ENC_RATE_CONTROL_METHOD_VARIABLE:
49 {
50 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Mode = D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_VBR;
51 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_VBR.TargetAvgBitRate =
52 picture->rc[0].target_bitrate;
53 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_VBR.PeakBitRate =
54 picture->rc[0].peak_bitrate;
55
56 if (D3D12_VIDEO_ENC_CBR_FORCE_VBV_EQUAL_BITRATE) {
57 debug_printf(
58 "[d3d12_video_encoder_av1] d3d12_video_encoder_update_current_rate_control_av1 "
59 "D3D12_VIDEO_ENC_CBR_FORCE_VBV_EQUAL_BITRATE environment variable is set, "
60 ", forcing VBV Size = VBV Initial Capacity = Target Bitrate = %" PRIu64 " (bits)\n",
61 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR.TargetBitRate);
62 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
63 D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_VBV_SIZES;
64 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR.VBVCapacity =
65 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR.TargetBitRate;
66 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR.InitialVBVFullness =
67 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR.TargetBitRate;
68 } else if (picture->rc[0].app_requested_hrd_buffer) {
69 debug_printf(
70 "[d3d12_video_encoder_av1] d3d12_video_encoder_update_current_rate_control_av1 HRD required by app,"
71 " setting VBV Size = %d (bits) - VBV Initial Capacity %d (bits)\n",
72 picture->rc[0].vbv_buffer_size,
73 picture->rc[0].vbv_buf_initial_size);
74 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
75 D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_VBV_SIZES;
76 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_VBR.VBVCapacity =
77 picture->rc[0].vbv_buffer_size;
78 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_VBR.InitialVBVFullness =
79 picture->rc[0].vbv_buf_initial_size;
80 }
81
82 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.max_frame_size = picture->rc[0].max_au_size;
83 if (picture->rc[0].max_au_size > 0) {
84 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
85 D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_MAX_FRAME_SIZE;
86 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_VBR.MaxFrameBitSize =
87 picture->rc[0].max_au_size;
88
89 debug_printf(
90 "[d3d12_video_encoder_av1] d3d12_video_encoder_update_current_rate_control_av1 "
91 "Upper layer requested explicit MaxFrameBitSize: %" PRIu64 "\n",
92 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_VBR.MaxFrameBitSize);
93 }
94
95 if (picture->rc[0].app_requested_qp_range) {
96 debug_printf("[d3d12_video_encoder_av1] d3d12_video_encoder_update_current_rate_control_av1 "
97 "Upper layer requested explicit MinQP: %d MaxQP: %d\n",
98 picture->rc[0].min_qp,
99 picture->rc[0].max_qp);
100 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
101 D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_QP_RANGE;
102 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_VBR.MinQP =
103 picture->rc[0].min_qp;
104 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_VBR.MaxQP =
105 picture->rc[0].max_qp;
106 }
107
108 if (picture->quality_modes.level > 0) {
109 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
110 D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_QUALITY_VS_SPEED;
111 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
112 D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_EXTENSION1_SUPPORT;
113
114 // Convert between D3D12 definition and PIPE definition
115 // D3D12: QualityVsSpeed must be in the range [0, D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT1.MaxQualityVsSpeed]
116 // The lower the value, the fastest the encode operation
117 // PIPE: The quality level range can be queried through the VAConfigAttribEncQualityRange attribute.
118 // A lower value means higher quality, and a value of 1 represents the highest quality.
119 // The quality level setting is used as a trade-off between quality and speed/power
120 // consumption, with higher quality corresponds to lower speed and higher power consumption.
121
122 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_VBR1.QualityVsSpeed =
123 pD3D12Enc->max_quality_levels - picture->quality_modes.level;
124 }
125
126 } break;
127 case PIPE_H2645_ENC_RATE_CONTROL_METHOD_QUALITY_VARIABLE:
128 {
129 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Mode = D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_QVBR;
130 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR.TargetAvgBitRate =
131 picture->rc[0].target_bitrate;
132 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR.PeakBitRate =
133 picture->rc[0].peak_bitrate;
134 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR.ConstantQualityTarget =
135 picture->rc[0].vbr_quality_factor;
136
137 if (D3D12_VIDEO_ENC_CBR_FORCE_VBV_EQUAL_BITRATE) {
138 debug_printf("[d3d12_video_encoder_av1] d3d12_video_encoder_update_current_rate_control_av1 "
139 "D3D12_VIDEO_ENC_CBR_FORCE_VBV_EQUAL_BITRATE environment variable is set, "
140 ", forcing VBV Size = VBV Initial Capacity = Target Bitrate = %" PRIu64 " (bits)\n",
141 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR1
142 .TargetAvgBitRate);
143 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
144 D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_VBV_SIZES;
145 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
146 D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_EXTENSION1_SUPPORT;
147 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR1.VBVCapacity =
148 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR1.TargetAvgBitRate;
149 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR1.InitialVBVFullness =
150 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR1.TargetAvgBitRate;
151 } else if (picture->rc[0].app_requested_hrd_buffer) {
152 debug_printf(
153 "[d3d12_video_encoder_av1] d3d12_video_encoder_update_current_rate_control_av1 HRD required by app,"
154 " setting VBV Size = %d (bits) - VBV Initial Capacity %d (bits)\n",
155 picture->rc[0].vbv_buffer_size,
156 picture->rc[0].vbv_buf_initial_size);
157 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
158 D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_VBV_SIZES;
159 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
160 D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_EXTENSION1_SUPPORT;
161 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR1.VBVCapacity =
162 picture->rc[0].vbv_buffer_size;
163 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR1.InitialVBVFullness =
164 picture->rc[0].vbv_buf_initial_size;
165 }
166 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.max_frame_size = picture->rc[0].max_au_size;
167 if (picture->rc[0].max_au_size > 0) {
168 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
169 D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_MAX_FRAME_SIZE;
170 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR.MaxFrameBitSize =
171 picture->rc[0].max_au_size;
172
173 debug_printf(
174 "[d3d12_video_encoder_av1] d3d12_video_encoder_update_current_rate_control_av1 "
175 "Upper layer requested explicit MaxFrameBitSize: %" PRIu64 "\n",
176 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR.MaxFrameBitSize);
177 }
178
179 if (picture->rc[0].app_requested_qp_range) {
180 debug_printf("[d3d12_video_encoder_av1] d3d12_video_encoder_update_current_rate_control_av1 "
181 "Upper layer requested explicit MinQP: %d MaxQP: %d\n",
182 picture->rc[0].min_qp,
183 picture->rc[0].max_qp);
184 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
185 D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_QP_RANGE;
186 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR.MinQP =
187 picture->rc[0].min_qp;
188 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR.MaxQP =
189 picture->rc[0].max_qp;
190 }
191
192 if (picture->quality_modes.level > 0) {
193 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
194 D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_QUALITY_VS_SPEED;
195 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
196 D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_EXTENSION1_SUPPORT;
197
198 // Convert between D3D12 definition and PIPE definition
199 // D3D12: QualityVsSpeed must be in the range [0, D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT1.MaxQualityVsSpeed]
200 // The lower the value, the fastest the encode operation
201 // PIPE: The quality level range can be queried through the VAConfigAttribEncQualityRange attribute.
202 // A lower value means higher quality, and a value of 1 represents the highest quality.
203 // The quality level setting is used as a trade-off between quality and speed/power
204 // consumption, with higher quality corresponds to lower speed and higher power consumption.
205
206 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR1.QualityVsSpeed =
207 pD3D12Enc->max_quality_levels - picture->quality_modes.level;
208 }
209
210 } break;
211 case PIPE_H2645_ENC_RATE_CONTROL_METHOD_CONSTANT_SKIP:
212 case PIPE_H2645_ENC_RATE_CONTROL_METHOD_CONSTANT:
213 {
214 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Mode = D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CBR;
215 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR.TargetBitRate =
216 picture->rc[0].target_bitrate;
217
218 /* For CBR mode, to guarantee bitrate of generated stream complies with
219 * target bitrate (e.g. no over +/-10%), vbv_buffer_size and initial capacity should be same
220 * as target bitrate. Controlled by OS env var D3D12_VIDEO_ENC_CBR_FORCE_VBV_EQUAL_BITRATE
221 */
222 if (D3D12_VIDEO_ENC_CBR_FORCE_VBV_EQUAL_BITRATE) {
223 debug_printf(
224 "[d3d12_video_encoder_av1] d3d12_video_encoder_update_current_rate_control_av1 "
225 "D3D12_VIDEO_ENC_CBR_FORCE_VBV_EQUAL_BITRATE environment variable is set, "
226 ", forcing VBV Size = VBV Initial Capacity = Target Bitrate = %" PRIu64 " (bits)\n",
227 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR.TargetBitRate);
228 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
229 D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_VBV_SIZES;
230 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR.VBVCapacity =
231 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR.TargetBitRate;
232 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR.InitialVBVFullness =
233 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR.TargetBitRate;
234 } else if (picture->rc[0].app_requested_hrd_buffer) {
235 debug_printf(
236 "[d3d12_video_encoder_av1] d3d12_video_encoder_update_current_rate_control_av1 HRD required by app,"
237 " setting VBV Size = %d (bits) - VBV Initial Capacity %d (bits)\n",
238 picture->rc[0].vbv_buffer_size,
239 picture->rc[0].vbv_buf_initial_size);
240 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
241 D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_VBV_SIZES;
242 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR.VBVCapacity =
243 picture->rc[0].vbv_buffer_size;
244 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR.InitialVBVFullness =
245 picture->rc[0].vbv_buf_initial_size;
246 }
247
248 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.max_frame_size = picture->rc[0].max_au_size;
249 if (picture->rc[0].max_au_size > 0) {
250 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
251 D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_MAX_FRAME_SIZE;
252 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR.MaxFrameBitSize =
253 picture->rc[0].max_au_size;
254
255 debug_printf(
256 "[d3d12_video_encoder_av1] d3d12_video_encoder_update_current_rate_control_av1 "
257 "Upper layer requested explicit MaxFrameBitSize: %" PRIu64 "\n",
258 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR.MaxFrameBitSize);
259 }
260
261 if (picture->rc[0].app_requested_qp_range) {
262 debug_printf("[d3d12_video_encoder_av1] d3d12_video_encoder_update_current_rate_control_av1 "
263 "Upper layer requested explicit MinQP: %d MaxQP: %d\n",
264 picture->rc[0].min_qp,
265 picture->rc[0].max_qp);
266
267 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
268 D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_QP_RANGE;
269 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR.MinQP =
270 picture->rc[0].min_qp;
271 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR.MaxQP =
272 picture->rc[0].max_qp;
273 }
274
275 if (picture->quality_modes.level > 0) {
276 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
277 D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_QUALITY_VS_SPEED;
278 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
279 D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_EXTENSION1_SUPPORT;
280
281 // Convert between D3D12 definition and PIPE definition
282 // D3D12: QualityVsSpeed must be in the range [0, D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT1.MaxQualityVsSpeed]
283 // The lower the value, the fastest the encode operation
284 // PIPE: The quality level range can be queried through the VAConfigAttribEncQualityRange attribute.
285 // A lower value means higher quality, and a value of 1 represents the highest quality.
286 // The quality level setting is used as a trade-off between quality and speed/power
287 // consumption, with higher quality corresponds to lower speed and higher power consumption.
288
289 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR1.QualityVsSpeed =
290 pD3D12Enc->max_quality_levels - picture->quality_modes.level;
291 }
292
293 } break;
294 case PIPE_H2645_ENC_RATE_CONTROL_METHOD_DISABLE:
295 {
296 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Mode = D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CQP;
297 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CQP
298 .ConstantQP_FullIntracodedFrame = picture->rc[0].app_requested_initial_qp ? picture->rc[0].qp : 0;
299 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CQP
300 .ConstantQP_InterPredictedFrame_PrevRefOnly =
301 picture->rc[0].app_requested_initial_qp ? picture->rc[0].qp : 0;
302 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CQP
303 .ConstantQP_InterPredictedFrame_BiDirectionalRef =
304 picture->rc[0].app_requested_initial_qp ? picture->rc[0].qp : 0;
305
306 if (picture->quality_modes.level > 0) {
307 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
308 D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_QUALITY_VS_SPEED;
309 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
310 D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_EXTENSION1_SUPPORT;
311 // Convert between D3D12 definition and PIPE definition
312 // D3D12: QualityVsSpeed must be in the range [0, D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT1.MaxQualityVsSpeed]
313 // The lower the value, the fastest the encode operation
314 // PIPE: The quality level range can be queried through the VAConfigAttribEncQualityRange attribute.
315 // A lower value means higher quality, and a value of 1 represents the highest quality.
316 // The quality level setting is used as a trade-off between quality and speed/power
317 // consumption, with higher quality corresponds to lower speed and higher power consumption.
318
319 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CQP1.QualityVsSpeed =
320 pD3D12Enc->max_quality_levels - picture->quality_modes.level;
321 }
322 } break;
323 default:
324 {
325 debug_printf("[d3d12_video_encoder_av1] d3d12_video_encoder_update_current_rate_control_av1 invalid RC "
326 "config, using default RC CQP mode\n");
327 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Mode = D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CQP;
328 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CQP
329 .ConstantQP_FullIntracodedFrame = 30;
330 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CQP
331 .ConstantQP_InterPredictedFrame_PrevRefOnly = 30;
332 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CQP
333 .ConstantQP_InterPredictedFrame_BiDirectionalRef = 30;
334 } break;
335 }
336 }
337
338 //
339 // Returns AV1 extra size on top of the usual base metadata layout size
340 //
341 size_t
d3d12_video_encoder_calculate_metadata_resolved_buffer_size_av1(uint32_t maxSliceNumber)342 d3d12_video_encoder_calculate_metadata_resolved_buffer_size_av1(uint32_t maxSliceNumber)
343 {
344 return sizeof(D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_TILES) +
345 sizeof(D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES);
346 }
347
348 void
d3d12_video_encoder_convert_d3d12_to_spec_level_av1(D3D12_VIDEO_ENCODER_AV1_LEVELS level12,uint32_t & specLevel)349 d3d12_video_encoder_convert_d3d12_to_spec_level_av1(D3D12_VIDEO_ENCODER_AV1_LEVELS level12, uint32_t &specLevel)
350 {
351 // Enum matches values as in seq_level_idx
352 specLevel = (uint32_t) level12;
353 }
354
355 void
d3d12_video_encoder_convert_d3d12_to_spec_tier_av1(D3D12_VIDEO_ENCODER_AV1_TIER tier12,uint32_t & specTier)356 d3d12_video_encoder_convert_d3d12_to_spec_tier_av1(D3D12_VIDEO_ENCODER_AV1_TIER tier12, uint32_t &specTier)
357 {
358 // Enum matches values as in seq_level_idx
359 specTier = (uint32_t) tier12;
360 }
361
362 void
d3d12_video_encoder_convert_spec_to_d3d12_level_av1(uint32_t specLevel,D3D12_VIDEO_ENCODER_AV1_LEVELS & level12)363 d3d12_video_encoder_convert_spec_to_d3d12_level_av1(uint32_t specLevel, D3D12_VIDEO_ENCODER_AV1_LEVELS &level12)
364 {
365 // Enum matches values as in seq_level_idx
366 level12 = (D3D12_VIDEO_ENCODER_AV1_LEVELS) specLevel;
367 }
368
369 void
d3d12_video_encoder_convert_spec_to_d3d12_tier_av1(uint32_t specTier,D3D12_VIDEO_ENCODER_AV1_TIER & tier12)370 d3d12_video_encoder_convert_spec_to_d3d12_tier_av1(uint32_t specTier, D3D12_VIDEO_ENCODER_AV1_TIER &tier12)
371 {
372 // Enum matches values as in seq_tier
373 tier12 = (D3D12_VIDEO_ENCODER_AV1_TIER) specTier;
374 }
375
376 uint32_t
d3d12_video_encoder_convert_d3d12_profile_to_spec_profile_av1(D3D12_VIDEO_ENCODER_AV1_PROFILE profile)377 d3d12_video_encoder_convert_d3d12_profile_to_spec_profile_av1(D3D12_VIDEO_ENCODER_AV1_PROFILE profile)
378 {
379 switch (profile) {
380 case D3D12_VIDEO_ENCODER_AV1_PROFILE_MAIN:
381 {
382 return 0;
383 } break;
384 default:
385 {
386 unreachable("Unsupported D3D12_VIDEO_ENCODER_AV1_PROFILE");
387 } break;
388 }
389 }
390
391 D3D12_VIDEO_ENCODER_AV1_PROFILE
d3d12_video_encoder_convert_profile_to_d3d12_enc_profile_av1(enum pipe_video_profile profile)392 d3d12_video_encoder_convert_profile_to_d3d12_enc_profile_av1(enum pipe_video_profile profile)
393 {
394 switch (profile) {
395 case PIPE_VIDEO_PROFILE_AV1_MAIN:
396 {
397 return D3D12_VIDEO_ENCODER_AV1_PROFILE_MAIN;
398 } break;
399 default:
400 {
401 unreachable("Unsupported pipe_video_profile");
402 } break;
403 }
404 }
405
406 bool
d3d12_video_encoder_update_av1_gop_configuration(struct d3d12_video_encoder * pD3D12Enc,pipe_av1_enc_picture_desc * picture)407 d3d12_video_encoder_update_av1_gop_configuration(struct d3d12_video_encoder *pD3D12Enc,
408 pipe_av1_enc_picture_desc *picture)
409 {
410 static_assert((unsigned) D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_KEY_FRAME == (unsigned) PIPE_AV1_ENC_FRAME_TYPE_KEY);
411 static_assert((unsigned) D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_INTER_FRAME == (unsigned) PIPE_AV1_ENC_FRAME_TYPE_INTER);
412 static_assert((unsigned) D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_INTRA_ONLY_FRAME ==
413 (unsigned) PIPE_AV1_ENC_FRAME_TYPE_INTRA_ONLY);
414 static_assert((unsigned) D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_SWITCH_FRAME ==
415 (unsigned) PIPE_AV1_ENC_FRAME_TYPE_SWITCH);
416
417 // Only update GOP when it begins
418 // This triggers DPB/encoder/heap re-creation, so only check on IDR when a GOP might change
419 if ((picture->frame_type == PIPE_AV1_ENC_FRAME_TYPE_INTRA_ONLY) ||
420 (picture->frame_type == PIPE_AV1_ENC_FRAME_TYPE_KEY)) {
421 uint32_t GOPLength = picture->seq.intra_period;
422 uint32_t PPicturePeriod = picture->seq.ip_period;
423
424 // Set dirty flag if m_AV1SequenceStructure changed
425 auto previousGOPConfig = pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_AV1SequenceStructure;
426 pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_AV1SequenceStructure = {
427 GOPLength,
428 PPicturePeriod,
429 };
430
431 if (memcmp(&previousGOPConfig,
432 &pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_AV1SequenceStructure,
433 sizeof(D3D12_VIDEO_ENCODER_AV1_SEQUENCE_STRUCTURE)) != 0) {
434 pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_gop;
435 }
436 }
437 return true;
438 }
439
440 D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE
d3d12_video_encoder_convert_av1_motion_configuration(struct d3d12_video_encoder * pD3D12Enc,pipe_av1_enc_picture_desc * picture)441 d3d12_video_encoder_convert_av1_motion_configuration(struct d3d12_video_encoder *pD3D12Enc,
442 pipe_av1_enc_picture_desc *picture)
443 {
444 return D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE_MAXIMUM;
445 }
446
447 bool
d3d12_video_encoder_compare_tile_config_av1(D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE currentTilesMode,D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE requestedTilesMode,D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_TILES currentTilePartition,D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_TILES requestedTilePartition)448 d3d12_video_encoder_compare_tile_config_av1(
449 D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE currentTilesMode,
450 D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE requestedTilesMode,
451 D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_TILES currentTilePartition,
452 D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_TILES requestedTilePartition)
453 {
454 if (currentTilesMode != requestedTilesMode)
455 return false;
456
457 if (memcmp(¤tTilePartition,
458 &requestedTilePartition,
459 sizeof(D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_TILES)))
460 return false;
461
462 return true;
463 }
464
465 ///
466 /// Tries to configurate the encoder using the requested tile configuration
467 ///
468 bool
d3d12_video_encoder_negotiate_current_av1_tiles_configuration(struct d3d12_video_encoder * pD3D12Enc,pipe_av1_enc_picture_desc * pAV1Pic)469 d3d12_video_encoder_negotiate_current_av1_tiles_configuration(struct d3d12_video_encoder *pD3D12Enc,
470 pipe_av1_enc_picture_desc *pAV1Pic)
471 {
472 D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_TILES tilePartition = {};
473 tilePartition.RowCount = pAV1Pic->tile_rows;
474 tilePartition.ColCount = pAV1Pic->tile_cols;
475 tilePartition.ContextUpdateTileId = pAV1Pic->context_update_tile_id;
476
477 // VA-API interface has 63 entries for tile cols/rows. When 64 requested,
478 // last one has to be calculated from the frame width/height in superblocks.
479
480 // Copy the tile col sizes (up to 63 defined in VA-API interface array sizes)
481 size_t accum_cols_sb = 0;
482 uint8_t src_cols_count = MIN2(63, pAV1Pic->tile_cols);
483 for (uint8_t i = 0; i < src_cols_count; i++) {
484 tilePartition.ColWidths[i] = pAV1Pic->width_in_sbs_minus_1[i] + 1;
485 accum_cols_sb += tilePartition.ColWidths[i];
486 }
487
488 // If there are 64 cols, calculate the last one manually as the difference
489 // between frame width in sb minus the accumulated tiles sb sizes
490 if (pAV1Pic->tile_cols == 64)
491 tilePartition.ColWidths[63] = pAV1Pic->frame_width_sb - accum_cols_sb;
492
493 // Copy the tile row sizes (up to 63 defined in VA-API interface array sizes)
494 size_t accum_rows_sb = 0;
495 uint8_t src_rows_count = MIN2(63, pAV1Pic->tile_rows);
496 for (uint8_t i = 0; i < src_rows_count; i++) {
497 tilePartition.RowHeights[i] = pAV1Pic->height_in_sbs_minus_1[i] + 1;
498 accum_rows_sb += tilePartition.RowHeights[i];
499 }
500
501 // If there are 64 rows, calculate the last one manually as the difference
502 // between frame height in sb minus the accumulated tiles sb sizes
503 if (pAV1Pic->tile_rows == 64)
504 tilePartition.RowHeights[63] = pAV1Pic->frame_height_sb - accum_rows_sb;
505
506 // Iterate the tiles and see if they're uniformly partitioned to decide
507 // which D3D12 tile mode to use
508 // Ignore the last row and last col width
509 bool tilesUniform = !D3D12_VIDEO_FORCE_TILE_MODE && util_is_power_of_two_or_zero(tilePartition.RowCount) &&
510 util_is_power_of_two_or_zero(tilePartition.ColCount);
511 // Iterate again now that the 63/64 edge case has been handled above.
512 for (uint8_t i = 1; tilesUniform && (i < tilePartition.RowCount - 1) /* Ignore last row */; i++)
513 tilesUniform = tilesUniform && (tilePartition.RowHeights[i - 1] == tilePartition.RowHeights[i]);
514
515 for (uint8_t i = 1; tilesUniform && (i < tilePartition.ColCount - 1) /* Ignore last col */; i++)
516 tilesUniform = tilesUniform && (tilePartition.ColWidths[i - 1] == tilePartition.ColWidths[i]);
517
518 D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE requestedTilesMode =
519 tilesUniform ? D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_GRID_PARTITION :
520 D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_CONFIGURABLE_GRID_PARTITION;
521
522 assert(pAV1Pic->num_tile_groups <= 128); // ARRAY_SIZE(TilesGroups)
523 pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigDesc.m_TilesConfig_AV1.TilesGroupsCount =
524 pAV1Pic->num_tile_groups;
525 for (uint8_t i = 0; i < pAV1Pic->num_tile_groups; i++) {
526 pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigDesc.m_TilesConfig_AV1.TilesGroups[i].tg_start =
527 pAV1Pic->tile_groups[i].tile_group_start;
528 pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigDesc.m_TilesConfig_AV1.TilesGroups[i].tg_end =
529 pAV1Pic->tile_groups[i].tile_group_end;
530 }
531
532 if (!d3d12_video_encoder_compare_tile_config_av1(
533 pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigMode,
534 requestedTilesMode,
535 pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigDesc.m_TilesConfig_AV1.TilesPartition,
536 tilePartition)) {
537 pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_slices;
538 }
539
540 // Update the encoder state with the tile config
541 pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigMode = requestedTilesMode;
542 pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigDesc.m_TilesConfig_AV1.TilesPartition = tilePartition;
543
544 D3D12_FEATURE_DATA_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_CONFIG capDataTilesSupport = {};
545 capDataTilesSupport.NodeIndex = pD3D12Enc->m_NodeIndex;
546 capDataTilesSupport.Codec = D3D12_VIDEO_ENCODER_CODEC_AV1;
547 capDataTilesSupport.Profile.DataSize = sizeof(pD3D12Enc->m_currentEncodeConfig.m_encoderProfileDesc.m_AV1Profile);
548 capDataTilesSupport.Profile.pAV1Profile = &pD3D12Enc->m_currentEncodeConfig.m_encoderProfileDesc.m_AV1Profile;
549 capDataTilesSupport.Level.DataSize = sizeof(pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_AV1LevelSetting);
550 capDataTilesSupport.Level.pAV1LevelSetting = &pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_AV1LevelSetting;
551 capDataTilesSupport.FrameResolution.Width = pAV1Pic->frame_width;
552 capDataTilesSupport.FrameResolution.Height = pAV1Pic->frame_height;
553 capDataTilesSupport.SubregionMode = requestedTilesMode;
554 capDataTilesSupport.CodecSupport.DataSize =
555 sizeof(pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1TileCaps);
556 capDataTilesSupport.CodecSupport.pAV1Support =
557 &pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1TileCaps;
558 pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1TileCaps.Use128SuperBlocks = false;
559 // return units in 64x64 default size
560 pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1TileCaps.TilesConfiguration =
561 pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigDesc.m_TilesConfig_AV1.TilesPartition;
562 HRESULT hr =
563 pD3D12Enc->m_spD3D12VideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_CONFIG,
564 &capDataTilesSupport,
565 sizeof(capDataTilesSupport));
566 if (FAILED(hr) || !capDataTilesSupport.IsSupported) {
567 debug_printf("D3D12_FEATURE_VIDEO_ENCODER_SUBREGION_TILES_SUPPORT HR (0x%x) error or IsSupported: (%d).\n",
568 hr,
569 capDataTilesSupport.IsSupported);
570 return false;
571 }
572
573 return true;
574 }
575
576 D3D12_VIDEO_ENCODER_AV1_CODEC_CONFIGURATION
d3d12_video_encoder_convert_av1_codec_configuration(struct d3d12_video_encoder * pD3D12Enc,pipe_av1_enc_picture_desc * pAV1Pic,bool & is_supported)577 d3d12_video_encoder_convert_av1_codec_configuration(struct d3d12_video_encoder *pD3D12Enc,
578 pipe_av1_enc_picture_desc *pAV1Pic,
579 bool &is_supported)
580 {
581 is_supported = true;
582 D3D12_VIDEO_ENCODER_AV1_CODEC_CONFIGURATION config = {
583 // D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAGS FeatureFlags;
584 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_NONE,
585 // UINT OrderHintBitsMinus1;
586 pAV1Pic->seq.order_hint_bits - 1,
587 };
588
589 //
590 // Query AV1 caps and store in m_currentEncodeCapabilities
591 //
592
593 D3D12_FEATURE_DATA_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT capCodecConfigData = {};
594 capCodecConfigData.NodeIndex = pD3D12Enc->m_NodeIndex;
595 capCodecConfigData.Codec = D3D12_VIDEO_ENCODER_CODEC_AV1;
596 D3D12_VIDEO_ENCODER_AV1_PROFILE prof =
597 d3d12_video_encoder_convert_profile_to_d3d12_enc_profile_av1(pD3D12Enc->base.profile);
598 capCodecConfigData.Profile.pAV1Profile = &prof;
599 capCodecConfigData.Profile.DataSize = sizeof(prof);
600 capCodecConfigData.CodecSupportLimits.pAV1Support =
601 &pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1CodecCaps;
602 capCodecConfigData.CodecSupportLimits.DataSize =
603 sizeof(pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1CodecCaps);
604
605 if (FAILED(
606 pD3D12Enc->m_spD3D12VideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT,
607 &capCodecConfigData,
608 sizeof(capCodecConfigData))) ||
609 !capCodecConfigData.IsSupported) {
610 debug_printf("D3D12_FEATURE_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT arguments not supported.\n");
611 is_supported = false;
612 return config;
613 }
614
615 // Enable features requested by gallium
616
617 if (pAV1Pic->seq.seq_bits.use_128x128_superblock)
618 config.FeatureFlags |= D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_128x128_SUPERBLOCK;
619 if (pAV1Pic->seq.seq_bits.enable_filter_intra)
620 config.FeatureFlags |= D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_FILTER_INTRA;
621 if (pAV1Pic->seq.seq_bits.enable_intra_edge_filter)
622 config.FeatureFlags |= D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_INTRA_EDGE_FILTER;
623 if (pAV1Pic->seq.seq_bits.enable_interintra_compound)
624 config.FeatureFlags |= D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_INTERINTRA_COMPOUND;
625 if (pAV1Pic->seq.seq_bits.enable_masked_compound)
626 config.FeatureFlags |= D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_MASKED_COMPOUND;
627 if (pAV1Pic->seq.seq_bits.enable_warped_motion)
628 config.FeatureFlags |= D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_WARPED_MOTION;
629 if (pAV1Pic->seq.seq_bits.enable_dual_filter)
630 config.FeatureFlags |= D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_DUAL_FILTER;
631 if (pAV1Pic->seq.seq_bits.enable_order_hint)
632 config.FeatureFlags |= D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_ORDER_HINT_TOOLS;
633 if (pAV1Pic->seq.seq_bits.enable_jnt_comp)
634 config.FeatureFlags |= D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_JNT_COMP;
635 if (pAV1Pic->seq.seq_bits.enable_ref_frame_mvs)
636 config.FeatureFlags |= D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_FRAME_REFERENCE_MOTION_VECTORS;
637 if (pAV1Pic->seq.seq_bits.enable_superres)
638 config.FeatureFlags |= D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_SUPER_RESOLUTION;
639 if (pAV1Pic->seq.seq_bits.enable_cdef)
640 config.FeatureFlags |= D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_CDEF_FILTERING;
641 if (pAV1Pic->seq.seq_bits.enable_restoration)
642 config.FeatureFlags |= D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_LOOP_RESTORATION_FILTER;
643
644 // No pipe flag for the following features, associated pic flags can be selected per frame. Enable if supported.
645
646 if ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1CodecCaps.SupportedFeatureFlags &
647 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_FORCED_INTEGER_MOTION_VECTORS) != 0) // seq_force_integer_mv
648 config.FeatureFlags |= D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_FORCED_INTEGER_MOTION_VECTORS;
649
650 if ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1CodecCaps.SupportedFeatureFlags &
651 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_PALETTE_ENCODING) != 0)
652 config.FeatureFlags |= D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_PALETTE_ENCODING;
653
654 if ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1CodecCaps.SupportedFeatureFlags &
655 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_INTRA_BLOCK_COPY) != 0)
656 config.FeatureFlags |= D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_INTRA_BLOCK_COPY;
657
658 if ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1CodecCaps.SupportedFeatureFlags &
659 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_LOOP_FILTER_DELTAS) != 0)
660 config.FeatureFlags |= D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_LOOP_FILTER_DELTAS;
661
662 if ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1CodecCaps.SupportedFeatureFlags &
663 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_QUANTIZATION_DELTAS) != 0)
664 config.FeatureFlags |= D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_QUANTIZATION_DELTAS;
665
666 if ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1CodecCaps.SupportedFeatureFlags &
667 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_QUANTIZATION_MATRIX) != 0)
668 config.FeatureFlags |= D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_QUANTIZATION_MATRIX;
669
670 if ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1CodecCaps.SupportedFeatureFlags &
671 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_REDUCED_TX_SET) != 0)
672 config.FeatureFlags |= D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_REDUCED_TX_SET;
673
674 if ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1CodecCaps.SupportedFeatureFlags &
675 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_MOTION_MODE_SWITCHABLE) != 0)
676 config.FeatureFlags |= D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_MOTION_MODE_SWITCHABLE;
677
678 if ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1CodecCaps.SupportedFeatureFlags &
679 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_ALLOW_HIGH_PRECISION_MV) != 0)
680 config.FeatureFlags |= D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_ALLOW_HIGH_PRECISION_MV;
681
682 //
683 // Add any missing mandatory/required features we didn't enable before
684 //
685 if ((config.FeatureFlags &
686 pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1CodecCaps.RequiredFeatureFlags) !=
687 pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1CodecCaps.RequiredFeatureFlags) {
688 debug_printf(
689 "[d3d12_video_encoder_convert_av1_codec_configuration] Adding required by caps but not selected already in "
690 "config.FeatureFlags...\n");
691
692 if (((config.FeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_128x128_SUPERBLOCK) == 0) &&
693 ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1CodecCaps.RequiredFeatureFlags &
694 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_128x128_SUPERBLOCK) != 0)) {
695 pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.RequiredNotRequestedFeatureFlags |=
696 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_128x128_SUPERBLOCK;
697 debug_printf(
698 "[d3d12_video_encoder_convert_av1_codec_configuration] Adding "
699 "D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_128x128_SUPERBLOCK required by caps but not selected already in "
700 "config.FeatureFlags...\n");
701 }
702
703 if (((config.FeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_FILTER_INTRA) == 0) &&
704 ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1CodecCaps.RequiredFeatureFlags &
705 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_FILTER_INTRA) != 0)) {
706 pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.RequiredNotRequestedFeatureFlags |=
707 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_FILTER_INTRA;
708 debug_printf(
709 "[d3d12_video_encoder_convert_av1_codec_configuration] "
710 "D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_FILTER_INTRA Adding required by caps but not selected already in "
711 "config.FeatureFlags...\n");
712 }
713
714 if (((config.FeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_INTRA_EDGE_FILTER) == 0) &&
715 ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1CodecCaps.RequiredFeatureFlags &
716 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_INTRA_EDGE_FILTER) != 0)) {
717 pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.RequiredNotRequestedFeatureFlags |=
718 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_INTRA_EDGE_FILTER;
719 debug_printf(
720 "[d3d12_video_encoder_convert_av1_codec_configuration] Adding "
721 "D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_INTRA_EDGE_FILTER required by caps but not selected already in "
722 "config.FeatureFlags...\n");
723 }
724
725 if (((config.FeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_INTERINTRA_COMPOUND) == 0) &&
726 ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1CodecCaps.RequiredFeatureFlags &
727 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_INTERINTRA_COMPOUND) != 0)) {
728 pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.RequiredNotRequestedFeatureFlags |=
729 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_INTERINTRA_COMPOUND;
730 debug_printf(
731 "[d3d12_video_encoder_convert_av1_codec_configuration] Adding "
732 "D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_INTERINTRA_COMPOUND required by caps but not selected already in "
733 "config.FeatureFlags...\n");
734 }
735
736 if (((config.FeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_MASKED_COMPOUND) == 0) &&
737 ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1CodecCaps.RequiredFeatureFlags &
738 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_MASKED_COMPOUND) != 0)) {
739 pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.RequiredNotRequestedFeatureFlags |=
740 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_MASKED_COMPOUND;
741 debug_printf(
742 "[d3d12_video_encoder_convert_av1_codec_configuration] Adding "
743 "D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_MASKED_COMPOUND required by caps but not selected already in "
744 "config.FeatureFlags...\n");
745 }
746
747 if (((config.FeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_WARPED_MOTION) == 0) &&
748 ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1CodecCaps.RequiredFeatureFlags &
749 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_WARPED_MOTION) != 0)) {
750 pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.RequiredNotRequestedFeatureFlags |=
751 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_WARPED_MOTION;
752 debug_printf(
753 "[d3d12_video_encoder_convert_av1_codec_configuration] "
754 "D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_WARPED_MOTION Adding required by caps but not selected already in "
755 "config.FeatureFlags...\n");
756 }
757
758 if (((config.FeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_DUAL_FILTER) == 0) &&
759 ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1CodecCaps.RequiredFeatureFlags &
760 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_DUAL_FILTER) != 0)) {
761 pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.RequiredNotRequestedFeatureFlags |=
762 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_DUAL_FILTER;
763 debug_printf("[d3d12_video_encoder_convert_av1_codec_configuration] == Adding required by caps but not "
764 "selected already in "
765 "config.FeatureFlags...\n");
766 }
767
768 if (((config.FeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_JNT_COMP) == 0) &&
769 ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1CodecCaps.RequiredFeatureFlags &
770 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_JNT_COMP) != 0)) {
771 pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.RequiredNotRequestedFeatureFlags |=
772 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_JNT_COMP;
773 debug_printf("[d3d12_video_encoder_convert_av1_codec_configuration] 0 Adding required by caps but not "
774 "selected already in "
775 "config.FeatureFlags...\n");
776 }
777
778 if (((config.FeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_FORCED_INTEGER_MOTION_VECTORS) == 0) &&
779 ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1CodecCaps.RequiredFeatureFlags &
780 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_FORCED_INTEGER_MOTION_VECTORS) != 0)) {
781 pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.RequiredNotRequestedFeatureFlags |=
782 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_FORCED_INTEGER_MOTION_VECTORS;
783 debug_printf(
784 "[d3d12_video_encoder_convert_av1_codec_configuration] Adding required by "
785 "D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_FORCED_INTEGER_MOTION_VECTORS caps but not selected already in "
786 "config.FeatureFlags...\n");
787 }
788
789 if (((config.FeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_SUPER_RESOLUTION) == 0) &&
790 ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1CodecCaps.RequiredFeatureFlags &
791 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_SUPER_RESOLUTION) != 0)) {
792 pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.RequiredNotRequestedFeatureFlags |=
793 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_SUPER_RESOLUTION;
794 debug_printf(
795 "[d3d12_video_encoder_convert_av1_codec_configuration] Adding "
796 "D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_SUPER_RESOLUTION required by caps but not selected already in "
797 "config.FeatureFlags...\n");
798 }
799
800 if (((config.FeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_LOOP_RESTORATION_FILTER) == 0) &&
801 ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1CodecCaps.RequiredFeatureFlags &
802 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_LOOP_RESTORATION_FILTER) != 0)) {
803 pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.RequiredNotRequestedFeatureFlags |=
804 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_LOOP_RESTORATION_FILTER;
805 debug_printf(
806 "[d3d12_video_encoder_convert_av1_codec_configuration] Adding "
807 "D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_LOOP_RESTORATION_FILTER required by caps but not selected already in "
808 "config.FeatureFlags...\n");
809 }
810
811 if (((config.FeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_PALETTE_ENCODING) == 0) &&
812 ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1CodecCaps.RequiredFeatureFlags &
813 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_PALETTE_ENCODING) != 0)) {
814 pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.RequiredNotRequestedFeatureFlags |=
815 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_PALETTE_ENCODING;
816 debug_printf(
817 "[d3d12_video_encoder_convert_av1_codec_configuration] Adding "
818 "D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_PALETTE_ENCODING required by caps but not selected already in "
819 "config.FeatureFlags...\n");
820 }
821
822 if (((config.FeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_CDEF_FILTERING) == 0) &&
823 ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1CodecCaps.RequiredFeatureFlags &
824 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_CDEF_FILTERING) != 0)) {
825 pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.RequiredNotRequestedFeatureFlags |=
826 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_CDEF_FILTERING;
827 debug_printf(
828 "[d3d12_video_encoder_convert_av1_codec_configuration] "
829 "D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_CDEF_FILTERING Adding required by caps but not selected already in "
830 "config.FeatureFlags...\n");
831 }
832
833 if (((config.FeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_INTRA_BLOCK_COPY) == 0) &&
834 ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1CodecCaps.RequiredFeatureFlags &
835 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_INTRA_BLOCK_COPY) != 0)) {
836 pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.RequiredNotRequestedFeatureFlags |=
837 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_INTRA_BLOCK_COPY;
838 debug_printf(
839 "[d3d12_video_encoder_convert_av1_codec_configuration] Adding "
840 "D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_INTRA_BLOCK_COPY required by caps but not selected already in "
841 "config.FeatureFlags...\n");
842 }
843
844 if (((config.FeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_FRAME_REFERENCE_MOTION_VECTORS) == 0) &&
845 ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1CodecCaps.RequiredFeatureFlags &
846 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_FRAME_REFERENCE_MOTION_VECTORS) != 0)) {
847 pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.RequiredNotRequestedFeatureFlags |=
848 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_FRAME_REFERENCE_MOTION_VECTORS;
849 debug_printf(
850 "[d3d12_video_encoder_convert_av1_codec_configuration] Adding required by "
851 "D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_FRAME_REFERENCE_MOTION_VECTORS caps but not selected already in "
852 "config.FeatureFlags...\n");
853 }
854
855 if (((config.FeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_ORDER_HINT_TOOLS) == 0) &&
856 ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1CodecCaps.RequiredFeatureFlags &
857 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_ORDER_HINT_TOOLS) != 0)) {
858 pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.RequiredNotRequestedFeatureFlags |=
859 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_ORDER_HINT_TOOLS;
860 debug_printf(
861 "[d3d12_video_encoder_convert_av1_codec_configuration] Adding "
862 "D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_ORDER_HINT_TOOLS required by caps but not selected already in "
863 "config.FeatureFlags...\n");
864 }
865
866 if (((config.FeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_AUTO_SEGMENTATION) == 0) &&
867 ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1CodecCaps.RequiredFeatureFlags &
868 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_AUTO_SEGMENTATION) != 0)) {
869 pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.RequiredNotRequestedFeatureFlags |=
870 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_AUTO_SEGMENTATION;
871 debug_printf(
872 "[d3d12_video_encoder_convert_av1_codec_configuration] Adding "
873 "D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_AUTO_SEGMENTATION required by caps but not selected already in "
874 "config.FeatureFlags...\n");
875 }
876
877 if (((config.FeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_CUSTOM_SEGMENTATION) == 0) &&
878 ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1CodecCaps.RequiredFeatureFlags &
879 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_CUSTOM_SEGMENTATION) != 0)) {
880 pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.RequiredNotRequestedFeatureFlags |=
881 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_CUSTOM_SEGMENTATION;
882 debug_printf(
883 "[d3d12_video_encoder_convert_av1_codec_configuration] Adding "
884 "D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_CUSTOM_SEGMENTATION required by caps but not selected already in "
885 "config.FeatureFlags...\n");
886 }
887
888 if (((config.FeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_LOOP_FILTER_DELTAS) == 0) &&
889 ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1CodecCaps.RequiredFeatureFlags &
890 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_LOOP_FILTER_DELTAS) != 0)) {
891 pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.RequiredNotRequestedFeatureFlags |=
892 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_LOOP_FILTER_DELTAS;
893 debug_printf(
894 "[d3d12_video_encoder_convert_av1_codec_configuration] Adding "
895 "D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_LOOP_FILTER_DELTAS required by caps but not selected already in "
896 "config.FeatureFlags...\n");
897 }
898
899 if (((config.FeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_QUANTIZATION_DELTAS) == 0) &&
900 ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1CodecCaps.RequiredFeatureFlags &
901 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_QUANTIZATION_DELTAS) != 0)) {
902 pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.RequiredNotRequestedFeatureFlags |=
903 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_QUANTIZATION_DELTAS;
904 debug_printf(
905 "[d3d12_video_encoder_convert_av1_codec_configuration] Adding "
906 "D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_QUANTIZATION_DELTAS required by caps but not selected already in "
907 "config.FeatureFlags...\n");
908 }
909
910 if (((config.FeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_QUANTIZATION_MATRIX) == 0) &&
911 ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1CodecCaps.RequiredFeatureFlags &
912 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_QUANTIZATION_MATRIX) != 0)) {
913 pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.RequiredNotRequestedFeatureFlags |=
914 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_QUANTIZATION_MATRIX;
915 debug_printf(
916 "[d3d12_video_encoder_convert_av1_codec_configuration] Adding "
917 "D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_QUANTIZATION_MATRIX required by caps but not selected already in "
918 "config.FeatureFlags...\n");
919 }
920
921 if (((config.FeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_REDUCED_TX_SET) == 0) &&
922 ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1CodecCaps.RequiredFeatureFlags &
923 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_REDUCED_TX_SET) != 0)) {
924 pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.RequiredNotRequestedFeatureFlags |=
925 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_REDUCED_TX_SET;
926 debug_printf(
927 "[d3d12_video_encoder_convert_av1_codec_configuration] "
928 "D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_REDUCED_TX_SET Adding required by caps but not selected already in "
929 "config.FeatureFlags...\n");
930 }
931
932 if (((config.FeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_MOTION_MODE_SWITCHABLE) == 0) &&
933 ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1CodecCaps.RequiredFeatureFlags &
934 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_MOTION_MODE_SWITCHABLE) != 0)) {
935 pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.RequiredNotRequestedFeatureFlags |=
936 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_MOTION_MODE_SWITCHABLE;
937 debug_printf(
938 "[d3d12_video_encoder_convert_av1_codec_configuration] Adding "
939 "D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_MOTION_MODE_SWITCHABLE required by caps but not selected already in "
940 "config.FeatureFlags...\n");
941 }
942
943 if (((config.FeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_ALLOW_HIGH_PRECISION_MV) == 0) &&
944 ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1CodecCaps.RequiredFeatureFlags &
945 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_ALLOW_HIGH_PRECISION_MV) != 0)) {
946 pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.RequiredNotRequestedFeatureFlags |=
947 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_ALLOW_HIGH_PRECISION_MV;
948 debug_printf(
949 "[d3d12_video_encoder_convert_av1_codec_configuration] Adding "
950 "D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_ALLOW_HIGH_PRECISION_MV required by caps but not selected already in "
951 "config.FeatureFlags...\n");
952 }
953
954 // Enable all required flags previously not selected
955 config.FeatureFlags |=
956 pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1CodecCaps.RequiredFeatureFlags;
957 }
958
959 // Check config.FeatureFlags against SupportedFeatureFlags and assign is_supported
960 if ((config.FeatureFlags &
961 pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1CodecCaps.SupportedFeatureFlags) !=
962 config.FeatureFlags) {
963 debug_printf(
964 "[d3d12_video_encoder_convert_av1_codec_configuration] AV1 Configuration flags requested 0x%x not supported "
965 "by "
966 "m_AV1CodecCaps.SupportedFeatureFlags 0x%x\n",
967 config.FeatureFlags,
968 pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1CodecCaps.SupportedFeatureFlags);
969
970 is_supported = false;
971 }
972
973 return config;
974 }
975
976 static bool
d3d12_video_encoder_update_intra_refresh_av1(struct d3d12_video_encoder * pD3D12Enc,D3D12_VIDEO_SAMPLE srcTextureDesc,struct pipe_av1_enc_picture_desc * picture)977 d3d12_video_encoder_update_intra_refresh_av1(struct d3d12_video_encoder *pD3D12Enc,
978 D3D12_VIDEO_SAMPLE srcTextureDesc,
979 struct pipe_av1_enc_picture_desc * picture)
980 {
981 if (picture->intra_refresh.mode != INTRA_REFRESH_MODE_NONE)
982 {
983 // D3D12 only supports row intra-refresh
984 if (picture->intra_refresh.mode != INTRA_REFRESH_MODE_UNIT_ROWS)
985 {
986 debug_printf("[d3d12_video_encoder_update_intra_refresh_av1] Unsupported INTRA_REFRESH_MODE %d\n", picture->intra_refresh.mode);
987 return false;
988 }
989
990 uint32_t sbSize = ((pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificConfigDesc.m_AV1Config.FeatureFlags &
991 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_128x128_SUPERBLOCK) != 0) ? 128u : 64u;
992 uint32_t total_frame_blocks = static_cast<uint32_t>(std::ceil(srcTextureDesc.Height / sbSize)) *
993 static_cast<uint32_t>(std::ceil(srcTextureDesc.Width / sbSize));
994 D3D12_VIDEO_ENCODER_INTRA_REFRESH targetIntraRefresh = {
995 D3D12_VIDEO_ENCODER_INTRA_REFRESH_MODE_ROW_BASED,
996 total_frame_blocks / picture->intra_refresh.region_size,
997 };
998 double ir_wave_progress = (picture->intra_refresh.offset == 0) ? 0 :
999 picture->intra_refresh.offset / (double) total_frame_blocks;
1000 pD3D12Enc->m_currentEncodeConfig.m_IntraRefreshCurrentFrameIndex =
1001 static_cast<uint32_t>(std::ceil(ir_wave_progress * targetIntraRefresh.IntraRefreshDuration));
1002
1003 // Set intra refresh state
1004 pD3D12Enc->m_currentEncodeConfig.m_IntraRefresh = targetIntraRefresh;
1005 // Need to send the sequence flag during all the IR duration
1006 pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_intra_refresh;
1007 } else {
1008 pD3D12Enc->m_currentEncodeConfig.m_IntraRefreshCurrentFrameIndex = 0;
1009 pD3D12Enc->m_currentEncodeConfig.m_IntraRefresh = {
1010 D3D12_VIDEO_ENCODER_INTRA_REFRESH_MODE_NONE,
1011 0,
1012 };
1013 }
1014
1015 return true;
1016 }
1017
1018 bool
d3d12_video_encoder_update_current_encoder_config_state_av1(struct d3d12_video_encoder * pD3D12Enc,D3D12_VIDEO_SAMPLE srcTextureDesc,struct pipe_picture_desc * picture)1019 d3d12_video_encoder_update_current_encoder_config_state_av1(struct d3d12_video_encoder *pD3D12Enc,
1020 D3D12_VIDEO_SAMPLE srcTextureDesc,
1021 struct pipe_picture_desc *picture)
1022 {
1023 struct pipe_av1_enc_picture_desc *av1Pic = (struct pipe_av1_enc_picture_desc *) picture;
1024
1025 // Reset reconfig dirty flags
1026 pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags = d3d12_video_encoder_config_dirty_flag_none;
1027 // Reset sequence changes flags
1028 pD3D12Enc->m_currentEncodeConfig.m_seqFlags = D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_FLAG_NONE;
1029
1030 // Set codec
1031 if (pD3D12Enc->m_currentEncodeConfig.m_encoderCodecDesc != D3D12_VIDEO_ENCODER_CODEC_AV1) {
1032 pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_codec;
1033 }
1034 pD3D12Enc->m_currentEncodeConfig.m_encoderCodecDesc = D3D12_VIDEO_ENCODER_CODEC_AV1;
1035
1036 // Set input format
1037 DXGI_FORMAT targetFmt = srcTextureDesc.Format.Format;
1038 if (pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo.Format != targetFmt) {
1039 pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_input_format;
1040 }
1041
1042 pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo = {};
1043 pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo.Format = targetFmt;
1044 HRESULT hr =
1045 pD3D12Enc->m_pD3D12Screen->dev->CheckFeatureSupport(D3D12_FEATURE_FORMAT_INFO,
1046 &pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo,
1047 sizeof(pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo));
1048 if (FAILED(hr)) {
1049 debug_printf("CheckFeatureSupport failed with HR 0x%x\n", hr);
1050 return false;
1051 }
1052
1053 // Set resolution (ie. frame_size)
1054 if ((pD3D12Enc->m_currentEncodeConfig.m_currentResolution.Width != srcTextureDesc.Width) ||
1055 (pD3D12Enc->m_currentEncodeConfig.m_currentResolution.Height != srcTextureDesc.Height)) {
1056 pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_resolution;
1057 }
1058 pD3D12Enc->m_currentEncodeConfig.m_currentResolution.Width = srcTextureDesc.Width;
1059 pD3D12Enc->m_currentEncodeConfig.m_currentResolution.Height = srcTextureDesc.Height;
1060
1061 // render_size
1062 pD3D12Enc->m_currentEncodeConfig.m_FrameCroppingCodecConfig.right = av1Pic->frame_width;
1063 pD3D12Enc->m_currentEncodeConfig.m_FrameCroppingCodecConfig.bottom = av1Pic->frame_height;
1064
1065 // Set profile
1066 auto targetProfile = d3d12_video_encoder_convert_profile_to_d3d12_enc_profile_av1(pD3D12Enc->base.profile);
1067 if (pD3D12Enc->m_currentEncodeConfig.m_encoderProfileDesc.m_AV1Profile != targetProfile) {
1068 pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_profile;
1069 }
1070 pD3D12Enc->m_currentEncodeConfig.m_encoderProfileDesc.m_AV1Profile = targetProfile;
1071
1072 // Set level and tier
1073 D3D12_VIDEO_ENCODER_AV1_LEVELS targetLevel = {};
1074 D3D12_VIDEO_ENCODER_AV1_TIER targetTier = {};
1075 d3d12_video_encoder_convert_spec_to_d3d12_level_av1(av1Pic->seq.level, targetLevel);
1076 d3d12_video_encoder_convert_spec_to_d3d12_tier_av1(av1Pic->seq.tier, targetTier);
1077
1078 if ((pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_AV1LevelSetting.Level != targetLevel) ||
1079 (pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_AV1LevelSetting.Tier != targetTier)) {
1080 pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_level;
1081 }
1082 pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_AV1LevelSetting.Tier = targetTier;
1083 pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_AV1LevelSetting.Level = targetLevel;
1084
1085 //
1086 // Validate caps support returned values against current settings
1087 //
1088 if (pD3D12Enc->m_currentEncodeConfig.m_encoderProfileDesc.m_AV1Profile !=
1089 pD3D12Enc->m_currentEncodeCapabilities.m_encoderSuggestedProfileDesc.m_AV1Profile) {
1090 debug_printf("[d3d12_video_encoder_av1] Warning: Requested D3D12_VIDEO_ENCODER_PROFILE_AV1 by upper layer: %d "
1091 "mismatches UMD suggested D3D12_VIDEO_ENCODER_PROFILE_AV1: %d\n",
1092 pD3D12Enc->m_currentEncodeConfig.m_encoderProfileDesc.m_AV1Profile,
1093 pD3D12Enc->m_currentEncodeCapabilities.m_encoderSuggestedProfileDesc.m_AV1Profile);
1094 }
1095
1096 if ((pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_AV1LevelSetting.Level !=
1097 pD3D12Enc->m_currentEncodeCapabilities.m_encoderLevelSuggestedDesc.m_AV1LevelSetting.Level) ||
1098 (pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_AV1LevelSetting.Tier !=
1099 pD3D12Enc->m_currentEncodeCapabilities.m_encoderLevelSuggestedDesc.m_AV1LevelSetting.Tier)) {
1100 debug_printf(
1101 "[d3d12_video_encoder_av1] Warning: Requested D3D12_VIDEO_ENCODER_LEVELS_AV1 by upper layer: level %d tier %d "
1102 "mismatches UMD suggested D3D12_VIDEO_ENCODER_LEVELS_AV1: level %d tier %d\n",
1103 pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_AV1LevelSetting.Level,
1104 pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_AV1LevelSetting.Tier,
1105 pD3D12Enc->m_currentEncodeCapabilities.m_encoderLevelSuggestedDesc.m_AV1LevelSetting.Level,
1106 pD3D12Enc->m_currentEncodeCapabilities.m_encoderLevelSuggestedDesc.m_AV1LevelSetting.Tier);
1107 }
1108
1109 // Set codec config
1110 bool is_supported = false;
1111 auto targetCodecConfig = d3d12_video_encoder_convert_av1_codec_configuration(pD3D12Enc, av1Pic, is_supported);
1112 if (!is_supported) {
1113 return false;
1114 }
1115
1116 if (memcmp(&pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificConfigDesc.m_AV1Config,
1117 &targetCodecConfig,
1118 sizeof(D3D12_VIDEO_ENCODER_AV1_CODEC_CONFIGURATION)) != 0) {
1119 pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_codec_config;
1120 }
1121 pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificConfigDesc.m_AV1Config = targetCodecConfig;
1122
1123 // Set rate control
1124 d3d12_video_encoder_update_current_rate_control_av1(pD3D12Enc, av1Pic);
1125
1126 // Set tiles config
1127 if (!d3d12_video_encoder_negotiate_current_av1_tiles_configuration(pD3D12Enc, av1Pic)) {
1128 debug_printf("d3d12_video_encoder_negotiate_current_av1_tiles_configuration failed!\n");
1129 return false;
1130 }
1131
1132 // Set GOP config
1133 if (!d3d12_video_encoder_update_av1_gop_configuration(pD3D12Enc, av1Pic)) {
1134 debug_printf("d3d12_video_encoder_update_av1_gop_configuration failed!\n");
1135 return false;
1136 }
1137
1138 // Set intra-refresh config
1139 if(!d3d12_video_encoder_update_intra_refresh_av1(pD3D12Enc, srcTextureDesc, av1Pic)) {
1140 debug_printf("d3d12_video_encoder_update_intra_refresh_av1 failed!\n");
1141 return false;
1142 }
1143
1144 // m_currentEncodeConfig.m_encoderPicParamsDesc pic params are set in d3d12_video_encoder_reconfigure_encoder_objects
1145 // after re-allocating objects if needed
1146
1147 // Set motion estimation config
1148 auto targetMotionLimit = d3d12_video_encoder_convert_av1_motion_configuration(pD3D12Enc, av1Pic);
1149 if (pD3D12Enc->m_currentEncodeConfig.m_encoderMotionPrecisionLimit != targetMotionLimit) {
1150 pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |=
1151 d3d12_video_encoder_config_dirty_flag_motion_precision_limit;
1152 }
1153 pD3D12Enc->m_currentEncodeConfig.m_encoderMotionPrecisionLimit = targetMotionLimit;
1154
1155 // Will call for d3d12 driver support based on the initial requested (non codec specific) features, then
1156 // try to fallback if any of them is not supported and return the negotiated d3d12 settings
1157 D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT1 capEncoderSupportData1 = {};
1158 if (!d3d12_video_encoder_negotiate_requested_features_and_d3d12_driver_caps(pD3D12Enc, capEncoderSupportData1)) {
1159 debug_printf("[d3d12_video_encoder_av1] After negotiating caps, D3D12_FEATURE_VIDEO_ENCODER_SUPPORT1 "
1160 "arguments are not supported - "
1161 "ValidationFlags: 0x%x - SupportFlags: 0x%x\n",
1162 capEncoderSupportData1.ValidationFlags,
1163 capEncoderSupportData1.SupportFlags);
1164 return false;
1165 }
1166
1167 pD3D12Enc->m_currentEncodeCapabilities.m_MaxSlicesInOutput = (av1Pic->tile_cols * av1Pic->tile_rows);
1168 if (pD3D12Enc->m_currentEncodeCapabilities.m_MaxSlicesInOutput >
1169 pD3D12Enc->m_currentEncodeCapabilities.m_currentResolutionSupportCaps.MaxSubregionsNumber) {
1170 debug_printf("[d3d12_video_encoder_av1] Desired number of subregions is not supported (higher than max "
1171 "reported slice number in query caps)\n.");
1172 return false;
1173 }
1174
1175 return true;
1176 }
1177
1178 /*
1179 * Called at begin_frame record time
1180 */
1181 void
d3d12_video_encoder_update_current_frame_pic_params_info_av1(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)1182 d3d12_video_encoder_update_current_frame_pic_params_info_av1(struct d3d12_video_encoder *pD3D12Enc,
1183 struct pipe_video_buffer *srcTexture,
1184 struct pipe_picture_desc *picture,
1185 D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA &picParams,
1186 bool &bUsedAsReference)
1187 {
1188 struct pipe_av1_enc_picture_desc *pAV1Pic = (struct pipe_av1_enc_picture_desc *) picture;
1189
1190 // Output param bUsedAsReference
1191 bUsedAsReference = (pAV1Pic->refresh_frame_flags != 0);
1192
1193 // D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAGS Flags;
1194 picParams.pAV1PicData->Flags = D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_NONE;
1195
1196 if (pAV1Pic->error_resilient_mode)
1197 picParams.pAV1PicData->Flags |= D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_ENABLE_ERROR_RESILIENT_MODE;
1198
1199 if (pAV1Pic->disable_cdf_update)
1200 picParams.pAV1PicData->Flags |= D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_DISABLE_CDF_UPDATE;
1201
1202 if (pAV1Pic->palette_mode_enable)
1203 picParams.pAV1PicData->Flags |= D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_ENABLE_PALETTE_ENCODING;
1204
1205 // Override if required feature
1206 if ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1CodecCaps.RequiredFeatureFlags &
1207 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_PALETTE_ENCODING) != 0) {
1208 debug_printf("[d3d12_video_encoder_update_current_frame_pic_params_info_av1] Overriding required feature "
1209 "D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_ENABLE_PALETTE_ENCODING\n");
1210 picParams.pAV1PicData->Flags |= D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_ENABLE_PALETTE_ENCODING;
1211 }
1212
1213 if (pAV1Pic->skip_mode_present)
1214 picParams.pAV1PicData->Flags |= D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_ENABLE_SKIP_MODE;
1215
1216 if ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1CodecCaps.RequiredFeatureFlags &
1217 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_SKIP_MODE_PRESENT) != 0) {
1218 debug_printf("[d3d12_video_encoder_update_current_frame_pic_params_info_av1] Overriding required feature "
1219 "D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_ENABLE_SKIP_MODE\n");
1220 picParams.pAV1PicData->Flags |= D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_ENABLE_SKIP_MODE;
1221 }
1222
1223 if (pAV1Pic->use_ref_frame_mvs)
1224 picParams.pAV1PicData->Flags |= D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_FRAME_REFERENCE_MOTION_VECTORS;
1225
1226 // Override if required feature
1227 if ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1CodecCaps.RequiredFeatureFlags &
1228 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_FRAME_REFERENCE_MOTION_VECTORS) != 0) {
1229 debug_printf("[d3d12_video_encoder_update_current_frame_pic_params_info_av1] Overriding required feature "
1230 "D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_FRAME_REFERENCE_MOTION_VECTORS\n");
1231 picParams.pAV1PicData->Flags |= D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_FRAME_REFERENCE_MOTION_VECTORS;
1232 }
1233
1234 // No pipe flag for force_integer_mv (D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_FORCE_INTEGER_MOTION_VECTORS)
1235 // choose default based on required/supported underlying codec flags
1236 if ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1CodecCaps.RequiredFeatureFlags &
1237 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_FORCED_INTEGER_MOTION_VECTORS) != 0) {
1238 debug_printf("[d3d12_video_encoder_update_current_frame_pic_params_info_av1] Overriding required feature "
1239 "D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_FORCE_INTEGER_MOTION_VECTORS\n");
1240 picParams.pAV1PicData->Flags |= D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_FORCE_INTEGER_MOTION_VECTORS;
1241 }
1242
1243 if (pAV1Pic->allow_intrabc)
1244 picParams.pAV1PicData->Flags |= D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_ALLOW_INTRA_BLOCK_COPY;
1245
1246 // Override if required feature
1247 if ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1CodecCaps.RequiredFeatureFlags &
1248 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_INTRA_BLOCK_COPY) != 0) {
1249 debug_printf("[d3d12_video_encoder_update_current_frame_pic_params_info_av1] Overriding required feature "
1250 "D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_ALLOW_INTRA_BLOCK_COPY\n");
1251 picParams.pAV1PicData->Flags |= D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_ALLOW_INTRA_BLOCK_COPY;
1252 }
1253
1254 if (pAV1Pic->use_superres)
1255 picParams.pAV1PicData->Flags |= D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_USE_SUPER_RESOLUTION;
1256
1257 if (pAV1Pic->disable_frame_end_update_cdf)
1258 picParams.pAV1PicData->Flags |= D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_DISABLE_FRAME_END_UPDATE_CDF;
1259
1260 // No pipe flag for D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_ENABLE_FRAME_SEGMENTATION_AUTO
1261 // choose default based on required/supported underlying codec flags
1262 if ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1CodecCaps.RequiredFeatureFlags &
1263 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_AUTO_SEGMENTATION) != 0) {
1264 debug_printf("[d3d12_video_encoder_update_current_frame_pic_params_info_av1] Overriding required feature "
1265 "D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_ENABLE_FRAME_SEGMENTATION_AUTO\n");
1266 picParams.pAV1PicData->Flags |= D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_ENABLE_FRAME_SEGMENTATION_AUTO;
1267 }
1268
1269 // No pipe flag for D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_ENABLE_FRAME_SEGMENTATION_CUSTOM
1270 // choose default based on required/supported underlying codec flags
1271 if ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1CodecCaps.RequiredFeatureFlags &
1272 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_CUSTOM_SEGMENTATION) != 0) {
1273 debug_printf("[d3d12_video_encoder_update_current_frame_pic_params_info_av1] Overriding required feature "
1274 "D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_ENABLE_FRAME_SEGMENTATION_CUSTOM\n");
1275 picParams.pAV1PicData->Flags |= D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_ENABLE_FRAME_SEGMENTATION_CUSTOM;
1276 assert(false); // Not implemented
1277 }
1278
1279 // No pipe flag for allow_warped_motion (D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_ENABLE_WARPED_MOTION)
1280 // choose default based on required/supported underlying codec flags
1281 if ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1CodecCaps.RequiredFeatureFlags &
1282 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_WARPED_MOTION) != 0) {
1283 debug_printf("[d3d12_video_encoder_update_current_frame_pic_params_info_av1] Overriding required feature "
1284 "D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_ENABLE_WARPED_MOTION\n");
1285 picParams.pAV1PicData->Flags |= D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_ENABLE_WARPED_MOTION;
1286 }
1287
1288 // Only enable if supported (there is no PIPE/VA cap flag for reduced_tx_set)
1289 if ((pAV1Pic->reduced_tx_set) &&
1290 (pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1CodecCaps.SupportedFeatureFlags &
1291 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_REDUCED_TX_SET) != 0) {
1292 picParams.pAV1PicData->Flags |= D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_REDUCED_TX_SET;
1293 }
1294
1295 // Override if required feature
1296 if ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1CodecCaps.RequiredFeatureFlags &
1297 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_REDUCED_TX_SET) != 0) {
1298 debug_printf("[d3d12_video_encoder_update_current_frame_pic_params_info_av1] Overriding required feature "
1299 "D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_REDUCED_TX_SET\n");
1300 picParams.pAV1PicData->Flags |= D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_REDUCED_TX_SET;
1301 }
1302
1303 // Only enable if supported
1304 if ((pAV1Pic->allow_high_precision_mv) &&
1305 (pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1CodecCaps.SupportedFeatureFlags &
1306 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_ALLOW_HIGH_PRECISION_MV) != 0) {
1307 picParams.pAV1PicData->Flags |= D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_ALLOW_HIGH_PRECISION_MV;
1308 }
1309
1310 // Override if required feature
1311 if ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1CodecCaps.RequiredFeatureFlags &
1312 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_ALLOW_HIGH_PRECISION_MV) != 0) {
1313 debug_printf("[d3d12_video_encoder_update_current_frame_pic_params_info_av1] Overriding required feature "
1314 "D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_ALLOW_HIGH_PRECISION_MV\n");
1315 picParams.pAV1PicData->Flags |= D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_ALLOW_HIGH_PRECISION_MV;
1316 }
1317
1318 // No pipe flag for is_motion_mode_switchable (D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_MOTION_MODE_SWITCHABLE)
1319 // choose default based on required/supported underlying codec flags
1320 if ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1CodecCaps.RequiredFeatureFlags &
1321 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_MOTION_MODE_SWITCHABLE) != 0) {
1322 debug_printf("[d3d12_video_encoder_update_current_frame_pic_params_info_av1] Overriding required feature "
1323 "D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_MOTION_MODE_SWITCHABLE\n");
1324 picParams.pAV1PicData->Flags |= D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_MOTION_MODE_SWITCHABLE;
1325 }
1326
1327 // D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE FrameType;
1328 // AV1 spec matches w/D3D12 enum definition
1329 picParams.pAV1PicData->FrameType = static_cast<D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE>(pAV1Pic->frame_type);
1330
1331 if (picParams.pAV1PicData->FrameType == D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_KEY_FRAME)
1332 debug_printf("Encoding FrameType: D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_KEY_FRAME\n");
1333 if (picParams.pAV1PicData->FrameType == D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_INTER_FRAME)
1334 debug_printf("Encoding FrameType: D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_INTER_FRAME\n");
1335 if (picParams.pAV1PicData->FrameType == D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_INTRA_ONLY_FRAME)
1336 debug_printf("Encoding FrameType: D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_INTRA_ONLY_FRAME\n");
1337 if (picParams.pAV1PicData->FrameType == D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_SWITCH_FRAME)
1338 debug_printf("Encoding FrameType: D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_SWITCH_FRAME\n");
1339
1340 // D3D12_VIDEO_ENCODER_AV1_COMP_PREDICTION_TYPE CompoundPredictionType;
1341 picParams.pAV1PicData->CompoundPredictionType = (pAV1Pic->compound_reference_mode == 0) ?
1342 D3D12_VIDEO_ENCODER_AV1_COMP_PREDICTION_TYPE_SINGLE_REFERENCE :
1343 D3D12_VIDEO_ENCODER_AV1_COMP_PREDICTION_TYPE_COMPOUND_REFERENCE;
1344
1345 // D3D12_VIDEO_ENCODER_AV1_INTERPOLATION_FILTERS InterpolationFilter;
1346 // AV1 spec matches w/D3D12 enum definition
1347 picParams.pAV1PicData->InterpolationFilter =
1348 static_cast<D3D12_VIDEO_ENCODER_AV1_INTERPOLATION_FILTERS>(pAV1Pic->interpolation_filter);
1349
1350 // Workaround for apps sending interpolation_filter values not supported even when reporting
1351 // them in pipe_av1_enc_cap_features_ext1.interpolation_filter. If D3D12 driver doesn't support
1352 // requested InterpolationFilter, fallback to the first supported by D3D12 driver
1353 if ( (pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1CodecCaps.SupportedInterpolationFilters &
1354 (1 << picParams.pAV1PicData->InterpolationFilter)) == 0 ) { /* See definition of D3D12_VIDEO_ENCODER_AV1_INTERPOLATION_FILTERS_FLAGS */
1355 debug_printf("[d3d12_video_encoder_update_current_frame_pic_params_info_av1] Requested interpolation_filter"
1356 " not supported in pipe_av1_enc_cap_features_ext1.interpolation_filter"
1357 ", auto selecting from D3D12 SupportedInterpolationFilters...");
1358 for(uint8_t i = D3D12_VIDEO_ENCODER_AV1_INTERPOLATION_FILTERS_EIGHTTAP; i <= D3D12_VIDEO_ENCODER_AV1_INTERPOLATION_FILTERS_SWITCHABLE; i++) {
1359 if ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1CodecCaps.SupportedInterpolationFilters &
1360 (1 << i)) /* See definition of D3D12_VIDEO_ENCODER_AV1_INTERPOLATION_FILTERS_FLAGS */ != 0) {
1361 picParams.pAV1PicData->InterpolationFilter = static_cast<D3D12_VIDEO_ENCODER_AV1_INTERPOLATION_FILTERS>(i);
1362 break;
1363 }
1364 }
1365 }
1366
1367 // D3D12_VIDEO_ENCODER_AV1_RESTORATION_CONFIG FrameRestorationConfig;
1368 // AV1 spec matches w/D3D12 FrameRestorationType enum definition
1369
1370 picParams.pAV1PicData->FrameRestorationConfig.FrameRestorationType[0] =
1371 static_cast<D3D12_VIDEO_ENCODER_AV1_RESTORATION_TYPE>(pAV1Pic->restoration.yframe_restoration_type);
1372 picParams.pAV1PicData->FrameRestorationConfig.FrameRestorationType[1] =
1373 static_cast<D3D12_VIDEO_ENCODER_AV1_RESTORATION_TYPE>(pAV1Pic->restoration.cbframe_restoration_type);
1374 picParams.pAV1PicData->FrameRestorationConfig.FrameRestorationType[2] =
1375 static_cast<D3D12_VIDEO_ENCODER_AV1_RESTORATION_TYPE>(pAV1Pic->restoration.crframe_restoration_type);
1376
1377 if (picParams.pAV1PicData->FrameRestorationConfig.FrameRestorationType[0] !=
1378 D3D12_VIDEO_ENCODER_AV1_RESTORATION_TYPE_DISABLED) {
1379 picParams.pAV1PicData->FrameRestorationConfig.LoopRestorationPixelSize[0] =
1380 d3d12_video_encoder_looprestorationsize_uint_to_d3d12_av1(1 << (6 + pAV1Pic->restoration.lr_unit_shift));
1381 }
1382
1383 if (picParams.pAV1PicData->FrameRestorationConfig.FrameRestorationType[1] !=
1384 D3D12_VIDEO_ENCODER_AV1_RESTORATION_TYPE_DISABLED) {
1385 picParams.pAV1PicData->FrameRestorationConfig.LoopRestorationPixelSize[1] =
1386 d3d12_video_encoder_looprestorationsize_uint_to_d3d12_av1(
1387 1 << (6 + pAV1Pic->restoration.lr_unit_shift - pAV1Pic->restoration.lr_uv_shift));
1388 }
1389
1390 if (picParams.pAV1PicData->FrameRestorationConfig.FrameRestorationType[2] !=
1391 D3D12_VIDEO_ENCODER_AV1_RESTORATION_TYPE_DISABLED) {
1392 picParams.pAV1PicData->FrameRestorationConfig.LoopRestorationPixelSize[2] =
1393 d3d12_video_encoder_looprestorationsize_uint_to_d3d12_av1(
1394 1 << (6 + pAV1Pic->restoration.lr_unit_shift - pAV1Pic->restoration.lr_uv_shift));
1395 }
1396
1397 // D3D12_VIDEO_ENCODER_AV1_TX_MODE TxMode;
1398 // AV1 spec matches w/D3D12 enum definition
1399 picParams.pAV1PicData->TxMode = static_cast<D3D12_VIDEO_ENCODER_AV1_TX_MODE>(pAV1Pic->tx_mode);
1400
1401 // Workaround for mismatch between VAAPI/D3D12 and TxMode support for all/some frame types
1402 // If D3D12 driver doesn't support requested TxMode, fallback to the first supported by D3D12
1403 // driver for the requested frame type
1404 if ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1CodecCaps.SupportedTxModes[picParams.pAV1PicData->FrameType] &
1405 (1 << picParams.pAV1PicData->TxMode)) == 0) /* See definition of D3D12_VIDEO_ENCODER_AV1_TX_MODE_FLAGS */ {
1406 debug_printf("[d3d12_video_encoder_update_current_frame_pic_params_info_av1] Requested tx_mode not supported"
1407 ", auto selecting from D3D12 SupportedTxModes for current frame type...");
1408 for(uint8_t i = D3D12_VIDEO_ENCODER_AV1_TX_MODE_ONLY4x4; i <= D3D12_VIDEO_ENCODER_AV1_TX_MODE_SELECT; i++) {
1409 if ((pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1CodecCaps.SupportedTxModes[picParams.pAV1PicData->FrameType] &
1410 (1 << i)) /* See definition of D3D12_VIDEO_ENCODER_AV1_TX_MODE_FLAGS */ != 0) {
1411 picParams.pAV1PicData->TxMode = static_cast<D3D12_VIDEO_ENCODER_AV1_TX_MODE>(i);
1412 break;
1413 }
1414 }
1415 }
1416
1417 // UINT SuperResDenominator;
1418 picParams.pAV1PicData->SuperResDenominator = pAV1Pic->superres_scale_denominator;
1419
1420 // UINT OrderHint;
1421 picParams.pAV1PicData->OrderHint = pAV1Pic->order_hint;
1422
1423 // UINT PictureIndex - Substract the last_key_frame_num to make it modulo KEY frame
1424 picParams.pAV1PicData->PictureIndex = pAV1Pic->frame_num - pAV1Pic->last_key_frame_num;
1425
1426 // UINT TemporalLayerIndexPlus1;
1427 assert(pAV1Pic->temporal_id == pAV1Pic->tg_obu_header.temporal_id);
1428 picParams.pAV1PicData->TemporalLayerIndexPlus1 = pAV1Pic->temporal_id + 1;
1429
1430 // UINT SpatialLayerIndexPlus1;
1431 picParams.pAV1PicData->SpatialLayerIndexPlus1 = pAV1Pic->tg_obu_header.spatial_id + 1;
1432
1433 //
1434 // Reference Pictures
1435 //
1436 {
1437 for (uint8_t i = 0; i < ARRAY_SIZE(picParams.pAV1PicData->ReferenceIndices); i++) {
1438 picParams.pAV1PicData->ReferenceIndices[i] = pAV1Pic->ref_frame_idx[i];
1439 }
1440
1441 bool FrameIsIntra = (picParams.pAV1PicData->FrameType == D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_INTRA_ONLY_FRAME ||
1442 picParams.pAV1PicData->FrameType == D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_KEY_FRAME);
1443 if (FrameIsIntra)
1444 picParams.pAV1PicData->PrimaryRefFrame = 7; /* PRIMARY_REF_NONE */
1445 else
1446 picParams.pAV1PicData->PrimaryRefFrame = pAV1Pic->primary_ref_frame;
1447 debug_printf("App requested primary_ref_frame: %" PRIu32 "\n", pAV1Pic->primary_ref_frame);
1448 picParams.pAV1PicData->RefreshFrameFlags = pAV1Pic->refresh_frame_flags;
1449 }
1450
1451 // D3D12_VIDEO_ENCODER_CODEC_AV1_LOOP_FILTER_CONFIG LoopFilter;
1452 picParams.pAV1PicData->LoopFilter.LoopFilterLevel[0] = pAV1Pic->loop_filter.filter_level[0];
1453 picParams.pAV1PicData->LoopFilter.LoopFilterLevel[1] = pAV1Pic->loop_filter.filter_level[1];
1454 picParams.pAV1PicData->LoopFilter.LoopFilterLevelU = pAV1Pic->loop_filter.filter_level_u;
1455 picParams.pAV1PicData->LoopFilter.LoopFilterLevelV = pAV1Pic->loop_filter.filter_level_v;
1456 picParams.pAV1PicData->LoopFilter.LoopFilterSharpnessLevel = pAV1Pic->loop_filter.sharpness_level;
1457 picParams.pAV1PicData->LoopFilter.LoopFilterDeltaEnabled = pAV1Pic->loop_filter.mode_ref_delta_enabled;
1458 picParams.pAV1PicData->LoopFilter.UpdateRefDelta = pAV1Pic->loop_filter.mode_ref_delta_update;
1459 if (picParams.pAV1PicData->LoopFilter.UpdateRefDelta) {
1460 for (uint8_t i = 0; i < ARRAY_SIZE(picParams.pAV1PicData->LoopFilter.RefDeltas); i++) {
1461 picParams.pAV1PicData->LoopFilter.RefDeltas[i] = pAV1Pic->loop_filter.ref_deltas[i];
1462 }
1463 }
1464 picParams.pAV1PicData->LoopFilter.UpdateModeDelta = pAV1Pic->loop_filter.mode_ref_delta_update;
1465 if (picParams.pAV1PicData->LoopFilter.UpdateModeDelta) {
1466 for (uint8_t i = 0; i < ARRAY_SIZE(picParams.pAV1PicData->LoopFilter.ModeDeltas); i++) {
1467 picParams.pAV1PicData->LoopFilter.ModeDeltas[i] = pAV1Pic->loop_filter.mode_deltas[i];
1468 }
1469 }
1470
1471 // D3D12_VIDEO_ENCODER_CODEC_AV1_LOOP_FILTER_DELTA_CONFIG LoopFilterDelta;
1472 picParams.pAV1PicData->LoopFilterDelta.DeltaLFMulti = pAV1Pic->loop_filter.delta_lf_multi;
1473 picParams.pAV1PicData->LoopFilterDelta.DeltaLFPresent = pAV1Pic->loop_filter.delta_lf_present;
1474 picParams.pAV1PicData->LoopFilterDelta.DeltaLFRes = pAV1Pic->loop_filter.delta_lf_res;
1475
1476 // D3D12_VIDEO_ENCODER_CODEC_AV1_QUANTIZATION_CONFIG Quantization;
1477 picParams.pAV1PicData->Quantization.BaseQIndex = pAV1Pic->quantization.base_qindex;
1478 picParams.pAV1PicData->Quantization.YDCDeltaQ = pAV1Pic->quantization.y_dc_delta_q;
1479 picParams.pAV1PicData->Quantization.UDCDeltaQ = pAV1Pic->quantization.u_dc_delta_q;
1480 picParams.pAV1PicData->Quantization.UACDeltaQ = pAV1Pic->quantization.u_ac_delta_q;
1481 picParams.pAV1PicData->Quantization.VDCDeltaQ = pAV1Pic->quantization.v_dc_delta_q;
1482 picParams.pAV1PicData->Quantization.VACDeltaQ = pAV1Pic->quantization.v_ac_delta_q;
1483 picParams.pAV1PicData->Quantization.UsingQMatrix = pAV1Pic->quantization.using_qmatrix;
1484 picParams.pAV1PicData->Quantization.QMY = pAV1Pic->quantization.qm_y;
1485 picParams.pAV1PicData->Quantization.QMU = pAV1Pic->quantization.qm_u;
1486 picParams.pAV1PicData->Quantization.QMV = pAV1Pic->quantization.qm_v;
1487
1488 // D3D12_VIDEO_ENCODER_CODEC_AV1_QUANTIZATION_DELTA_CONFIG QuantizationDelta;
1489 picParams.pAV1PicData->QuantizationDelta.DeltaQPresent = pAV1Pic->quantization.delta_q_present;
1490 picParams.pAV1PicData->QuantizationDelta.DeltaQRes = pAV1Pic->quantization.delta_q_res;
1491
1492 // D3D12_VIDEO_ENCODER_AV1_CDEF_CONFIG CDEF;
1493 picParams.pAV1PicData->CDEF.CdefBits = pAV1Pic->cdef.cdef_bits;
1494 picParams.pAV1PicData->CDEF.CdefDampingMinus3 = pAV1Pic->cdef.cdef_damping_minus_3;
1495 for (uint32_t i = 0; i < 8; i++) {
1496 picParams.pAV1PicData->CDEF.CdefYPriStrength[i] = (pAV1Pic->cdef.cdef_y_strengths[i] >> 2);
1497 picParams.pAV1PicData->CDEF.CdefYSecStrength[i] = (pAV1Pic->cdef.cdef_y_strengths[i] & 0x03);
1498 picParams.pAV1PicData->CDEF.CdefUVPriStrength[i] = (pAV1Pic->cdef.cdef_uv_strengths[i] >> 2);
1499 picParams.pAV1PicData->CDEF.CdefUVSecStrength[i] = (pAV1Pic->cdef.cdef_uv_strengths[i] & 0x03);
1500 }
1501
1502 //
1503 // Set values for mandatory but not requested features (ie. RequiredFeature flags reported by driver not requested
1504 // by pipe)
1505 //
1506
1507 // For the ones that are more trivial (ie. 128x128 SB) than enabling their flag, and have more parameters to be
1508 // set (ie Restoration Filter) Set defaults based on such feature driver d3d12 caps
1509
1510 // These are a trivial flag enabling
1511 // D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_128x128_SUPERBLOCK
1512 // D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_FILTER_INTRA
1513 // D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_INTRA_EDGE_FILTER
1514 // D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_INTERINTRA_COMPOUND
1515 // D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_MASKED_COMPOUND
1516 // D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_WARPED_MOTION
1517 // D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_DUAL_FILTER
1518 // D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_JNT_COMP
1519 // D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_FORCED_INTEGER_MOTION_VECTORS
1520 // D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_SUPER_RESOLUTION
1521 // D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_PALETTE_ENCODING
1522 // D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_INTRA_BLOCK_COPY
1523 // D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_FRAME_REFERENCE_MOTION_VECTORS
1524 // D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_ORDER_HINT_TOOLS
1525 // D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_REDUCED_TX_SET
1526 // D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_MOTION_MODE_SWITCHABLE
1527 // D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_ALLOW_HIGH_PRECISION_MV
1528
1529 // If driver requires these, can use post encode values to enforce specific values
1530 // D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_CDEF_FILTERING
1531 // D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_AUTO_SEGMENTATION // Only useful with post encode values as driver
1532 // controls D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_CUSTOM_SEGMENTATION // There are more Segmentation caps in
1533 // D3D12_VIDEO_ENCODER_AV1_CODEC_CONFIGURATION_SUPPORT for these one too
1534 // D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_LOOP_FILTER_DELTAS
1535 // D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_QUANTIZATION_DELTAS
1536 // D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_QUANTIZATION_MATRIX
1537
1538 // If driver requires this one, use driver restoration caps to set default values
1539 // D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_LOOP_RESTORATION_FILTER
1540 if (pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.RequiredNotRequestedFeatureFlags &
1541 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_LOOP_RESTORATION_FILTER) {
1542 debug_printf(
1543 "[d3d12_video_encoder_update_current_frame_pic_params_info_av1] Adding default params for "
1544 "D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_LOOP_RESTORATION_FILTER required by caps but not selected already in "
1545 "config.FeatureFlags...\n");
1546
1547 // Set Y, U, V luma plane restoration params
1548 for (uint32_t planeIdx = 0; planeIdx < 3; planeIdx++) {
1549 // Let's see which filters and with which sizes are supported for planeIdx
1550 bool foundSupportedFilter = false;
1551 for (uint32_t filterIdx = 0; ((filterIdx < 3) && !foundSupportedFilter); filterIdx++) {
1552 auto curFilterSupport = pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps
1553 .m_AV1CodecCaps.SupportedRestorationParams[filterIdx][planeIdx];
1554 for (uint32_t curFilterSize = D3D12_VIDEO_ENCODER_AV1_RESTORATION_TILESIZE_32x32;
1555 ((curFilterSize <= D3D12_VIDEO_ENCODER_AV1_RESTORATION_TILESIZE_256x256) && !foundSupportedFilter);
1556 curFilterSize++) {
1557
1558 // Check if there's support for curFilter on CurPlane and choose the first supported restoration size
1559 // If yes, set restoration params for planeIdx
1560 if (curFilterSupport &
1561 (1 << (curFilterSize - 1))) { /* Converts D3D12_VIDEO_ENCODER_AV1_RESTORATION_TILESIZE definition
1562 into D3D12_VIDEO_ENCODER_AV1_RESTORATION_SUPPORT_FLAGS definition */
1563 {
1564 foundSupportedFilter = true;
1565 // As per d3d12 spec filterIdx corresponds to D3D12_VIDEO_ENCODER_AV1_RESTORATION_TYPE - 1
1566 // (SupportedRestorationParams definition skips D3D12_VIDEO_ENCODER_AV1_RESTORATION_TYPE_DISABLED)
1567 D3D12_VIDEO_ENCODER_AV1_RESTORATION_TYPE curFilter =
1568 static_cast<D3D12_VIDEO_ENCODER_AV1_RESTORATION_TYPE>(filterIdx + 1);
1569
1570 picParams.pAV1PicData->FrameRestorationConfig.FrameRestorationType[planeIdx] = curFilter;
1571 picParams.pAV1PicData->FrameRestorationConfig.LoopRestorationPixelSize[planeIdx] =
1572 static_cast<D3D12_VIDEO_ENCODER_AV1_RESTORATION_TILESIZE>(
1573 curFilterSize); /* loop uses enum type */
1574 }
1575 }
1576 }
1577 }
1578 }
1579 }
1580
1581 // Save state snapshot from record time to resolve headers at get_feedback time
1582 uint64_t current_metadata_slot = (pD3D12Enc->m_fenceValue % D3D12_VIDEO_ENC_METADATA_BUFFERS_COUNT);
1583 pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].m_associatedEncodeCapabilities =
1584 pD3D12Enc->m_currentEncodeCapabilities;
1585 pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].m_associatedEncodeConfig =
1586 pD3D12Enc->m_currentEncodeConfig;
1587 pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].m_CodecSpecificData.AV1HeadersInfo.enable_frame_obu =
1588 pAV1Pic->enable_frame_obu;
1589 pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].m_CodecSpecificData.AV1HeadersInfo.obu_has_size_field =
1590 (pAV1Pic->tg_obu_header.obu_has_size_field == 1);
1591 // Disabling for now as the libva spec does not allow these but some apps send down anyway. It's possible in the future
1592 // the libva spec may be retro-fitted to allow this given existing apps in the wild doing it.
1593 // pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot]
1594 // .m_CodecSpecificData.AV1HeadersInfo.temporal_delim_rendered = pAV1Pic->temporal_delim_rendered;
1595
1596 if ((pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags & D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_DELTA_QP) != 0)
1597 {
1598 // Use 16 bit qpmap array for AV1 picparams (-255, 255 range and int16_t pRateControlQPMap type)
1599 const int32_t av1_min_delta_qp = -255;
1600 const int32_t av1_max_delta_qp = 255;
1601 d3d12_video_encoder_update_picparams_region_of_interest_qpmap(
1602 pD3D12Enc,
1603 &pAV1Pic->roi,
1604 av1_min_delta_qp,
1605 av1_max_delta_qp,
1606 pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_pRateControlQPMap16Bit);
1607 picParams.pAV1PicData->pRateControlQPMap = pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_pRateControlQPMap16Bit.data();
1608 picParams.pAV1PicData->QPMapValuesCount = pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_pRateControlQPMap16Bit.size();
1609 }
1610 }
1611
1612 void
fill_av1_seq_header(EncodedBitstreamResolvedMetadata & associatedMetadata,av1_seq_header_t * seq_header)1613 fill_av1_seq_header(EncodedBitstreamResolvedMetadata &associatedMetadata, av1_seq_header_t *seq_header)
1614 {
1615 // Set all zero by default
1616 memset(seq_header, 0, sizeof(av1_seq_header_t));
1617
1618 seq_header->seq_profile = d3d12_video_encoder_convert_d3d12_profile_to_spec_profile_av1(
1619 associatedMetadata.m_associatedEncodeConfig.m_encoderProfileDesc.m_AV1Profile);
1620 // seq_header->still_picture; // coded in bitstream by default as 0
1621 // seq_header->reduced_still_picture_header; // coded in bitstream by default as 0
1622 // seq_header->timing_info_present_flag; // coded in bitstream by default as 0
1623 // seq_header->decoder_model_info_present_flag; // coded in bitstream by default as 0
1624 // seq_header->operating_points_cnt_minus_1; // memset default as 0
1625 // seq_header->operating_point_idc[32]; // memset default as 0
1626 d3d12_video_encoder_convert_d3d12_to_spec_level_av1(
1627 associatedMetadata.m_associatedEncodeConfig.m_encoderLevelDesc.m_AV1LevelSetting.Level,
1628 seq_header->seq_level_idx[0]);
1629 d3d12_video_encoder_convert_d3d12_to_spec_tier_av1(
1630 associatedMetadata.m_associatedEncodeConfig.m_encoderLevelDesc.m_AV1LevelSetting.Tier,
1631 seq_header->seq_tier[0]);
1632 // seq_header->decoder_model_present_for_this_op[32]; // memset default as 0
1633 // seq_header->initial_display_delay_present_flag; // coded in bitstream by default as 0
1634 // seq_header->initial_display_delay_minus_1[32];
1635 // seq_header->initial_display_delay_present_for_this_op[32]
1636 // seq_header->frame_width_bits; // coded in bitstream by default as 16
1637 // seq_header->frame_height_bits; // coded in bitstream by default as 16
1638
1639 // frame_size (comes from input texture size)
1640 seq_header->max_frame_width = associatedMetadata.m_associatedEncodeConfig.m_currentResolution.Width;
1641 seq_header->max_frame_height = associatedMetadata.m_associatedEncodeConfig.m_currentResolution.Height;
1642
1643 // seq_header->frame_id_numbers_present_flag; // coded in bitstream by default as 0
1644 seq_header->use_128x128_superblock =
1645 ((associatedMetadata.m_associatedEncodeConfig.m_encoderCodecSpecificConfigDesc.m_AV1Config.FeatureFlags &
1646 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_128x128_SUPERBLOCK) != 0) ?
1647 1 :
1648 0;
1649 seq_header->enable_filter_intra =
1650 ((associatedMetadata.m_associatedEncodeConfig.m_encoderCodecSpecificConfigDesc.m_AV1Config.FeatureFlags &
1651 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_FILTER_INTRA) != 0) ?
1652 1 :
1653 0;
1654 seq_header->enable_intra_edge_filter =
1655 ((associatedMetadata.m_associatedEncodeConfig.m_encoderCodecSpecificConfigDesc.m_AV1Config.FeatureFlags &
1656 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_INTRA_EDGE_FILTER) != 0) ?
1657 1 :
1658 0;
1659 seq_header->enable_interintra_compound =
1660 ((associatedMetadata.m_associatedEncodeConfig.m_encoderCodecSpecificConfigDesc.m_AV1Config.FeatureFlags &
1661 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_INTERINTRA_COMPOUND) != 0) ?
1662 1 :
1663 0;
1664 seq_header->enable_masked_compound =
1665 ((associatedMetadata.m_associatedEncodeConfig.m_encoderCodecSpecificConfigDesc.m_AV1Config.FeatureFlags &
1666 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_MASKED_COMPOUND) != 0) ?
1667 1 :
1668 0;
1669 seq_header->enable_warped_motion =
1670 ((associatedMetadata.m_associatedEncodeConfig.m_encoderCodecSpecificConfigDesc.m_AV1Config.FeatureFlags &
1671 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_WARPED_MOTION) != 0) ?
1672 1 :
1673 0;
1674 seq_header->enable_dual_filter =
1675 ((associatedMetadata.m_associatedEncodeConfig.m_encoderCodecSpecificConfigDesc.m_AV1Config.FeatureFlags &
1676 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_DUAL_FILTER) != 0) ?
1677 1 :
1678 0;
1679 seq_header->enable_order_hint =
1680 ((associatedMetadata.m_associatedEncodeConfig.m_encoderCodecSpecificConfigDesc.m_AV1Config.FeatureFlags &
1681 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_ORDER_HINT_TOOLS) != 0) ?
1682 1 :
1683 0;
1684 seq_header->enable_jnt_comp =
1685 ((associatedMetadata.m_associatedEncodeConfig.m_encoderCodecSpecificConfigDesc.m_AV1Config.FeatureFlags &
1686 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_JNT_COMP) != 0) ?
1687 1 :
1688 0;
1689 seq_header->enable_ref_frame_mvs =
1690 ((associatedMetadata.m_associatedEncodeConfig.m_encoderCodecSpecificConfigDesc.m_AV1Config.FeatureFlags &
1691 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_FRAME_REFERENCE_MOTION_VECTORS) != 0) ?
1692 1 :
1693 0;
1694 seq_header->seq_choose_screen_content_tools = 0; // coded in bitstream by default as 0
1695 seq_header->seq_force_screen_content_tools = 0; // coded in bitstream by default as 0
1696 seq_header->seq_choose_integer_mv = 0; // coded in bitstream by default as 0
1697 seq_header->seq_force_integer_mv = 0; // coded in bitstream by default as 0
1698 seq_header->order_hint_bits_minus1 =
1699 associatedMetadata.m_associatedEncodeConfig.m_encoderCodecSpecificConfigDesc.m_AV1Config.OrderHintBitsMinus1;
1700 seq_header->enable_superres =
1701 ((associatedMetadata.m_associatedEncodeConfig.m_encoderCodecSpecificConfigDesc.m_AV1Config.FeatureFlags &
1702 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_SUPER_RESOLUTION) != 0) ?
1703 1 :
1704 0;
1705 seq_header->enable_cdef =
1706 ((associatedMetadata.m_associatedEncodeConfig.m_encoderCodecSpecificConfigDesc.m_AV1Config.FeatureFlags &
1707 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_CDEF_FILTERING) != 0) ?
1708 1 :
1709 0;
1710 seq_header->enable_restoration =
1711 ((associatedMetadata.m_associatedEncodeConfig.m_encoderCodecSpecificConfigDesc.m_AV1Config.FeatureFlags &
1712 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_LOOP_RESTORATION_FILTER) != 0) ?
1713 1 :
1714 0;
1715
1716 seq_header->color_config.bit_depth = associatedMetadata.m_associatedEncodeConfig.m_encodeFormatInfo.Format;
1717 // seq_header->color_config.mono_chrome; // coded in bitstream by default as 0
1718 // seq_header->color_config.color_description_present_flag; // memset default as 0
1719 // seq_header->color_config.color_primaries; // memset default as 0
1720 // seq_header->color_config.transfer_characteristics; // memset default as 0
1721 // seq_header->color_config.matrix_coefficients; // memset default as 0
1722 // seq_header->color_config.color_range; // memset default as 0
1723 seq_header->color_config.chroma_sample_position = 0; // CSP_UNKNOWN
1724 seq_header->color_config.subsampling_x = 1; // DX12 4:2:0 only
1725 seq_header->color_config.subsampling_y = 1; // DX12 4:2:0 only
1726 seq_header->color_config.separate_uv_delta_q = 1;
1727
1728 // seq_header->film_grain_params_present; // coded in bitstream by default as 1
1729 }
1730
1731 void
fill_av1_pic_header(EncodedBitstreamResolvedMetadata & associatedMetadata,av1_pic_header_t * pic_header,const av1_seq_header_t * seqHdr,const D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES * pParsedPostEncodeValues,const D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_TILES * pParsedTilePartitions)1732 fill_av1_pic_header(EncodedBitstreamResolvedMetadata &associatedMetadata,
1733 av1_pic_header_t *pic_header,
1734 const av1_seq_header_t *seqHdr,
1735 const D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES *pParsedPostEncodeValues,
1736 const D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_TILES *pParsedTilePartitions)
1737 {
1738 // Set all zero by default
1739 memset(pic_header, 0, sizeof(av1_pic_header_t));
1740
1741 {
1742 pic_header->quantization_params = pParsedPostEncodeValues->Quantization;
1743
1744 debug_printf("[d3d12_video_enc_av1] Parsing driver post encode "
1745 "values...D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES_FLAG_QUANTIZATION\n");
1746
1747 debug_printf("Post encode quantization_params.BaseQIndex: %" PRIu64 "\n",
1748 pic_header->quantization_params.BaseQIndex);
1749 debug_printf("Post encode quantization_params.YDCDeltaQ: %" PRId64 "\n",
1750 pic_header->quantization_params.YDCDeltaQ);
1751 debug_printf("Post encode quantization_params.UDCDeltaQ: %" PRId64 "\n",
1752 pic_header->quantization_params.UDCDeltaQ);
1753 debug_printf("Post encode quantization_params.UACDeltaQ: %" PRId64 "\n",
1754 pic_header->quantization_params.UACDeltaQ);
1755 debug_printf("Post encode quantization_params.VDCDeltaQ: %" PRId64 "\n",
1756 pic_header->quantization_params.VDCDeltaQ);
1757 debug_printf("Post encode quantization_params.VACDeltaQ: %" PRId64 "\n",
1758 pic_header->quantization_params.VACDeltaQ);
1759 debug_printf("Post encode quantization_params.UsingQMatrix: %" PRIu64 "\n",
1760 pic_header->quantization_params.UsingQMatrix);
1761 debug_printf("Post encode quantization_params.QMY: %" PRIu64 "\n", pic_header->quantization_params.QMY);
1762 debug_printf("Post encode quantization_params.QMU: %" PRIu64 "\n", pic_header->quantization_params.QMU);
1763 debug_printf("Post encode quantization_params.QMV: %" PRIu64 "\n", pic_header->quantization_params.QMV);
1764 }
1765
1766 pic_header->segmentation_enabled = 0;
1767 if ((associatedMetadata.m_associatedEncodeConfig.m_encoderPicParamsDesc.m_AV1PicData.Flags &
1768 D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_ENABLE_FRAME_SEGMENTATION_AUTO) != 0) {
1769
1770 // The segmentation info comes from the driver
1771 pic_header->segmentation_config = pParsedPostEncodeValues->SegmentationConfig;
1772 pic_header->segmentation_enabled = (pic_header->segmentation_config.NumSegments != 0);
1773 }
1774
1775 {
1776 debug_printf("[d3d12_video_enc_av1] Parsing driver post encode "
1777 "values...D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES_FLAG_QUANTIZATION_DELTA\n");
1778 pic_header->delta_q_params = pParsedPostEncodeValues->QuantizationDelta;
1779
1780 debug_printf("Post encode delta_q_params.DeltaQPresent: %" PRIu64 "\n", pic_header->delta_q_params.DeltaQPresent);
1781 debug_printf("Post encode delta_q_params.DeltaQRes: %" PRIu64 "\n", pic_header->delta_q_params.DeltaQRes);
1782 }
1783
1784 {
1785 debug_printf("[d3d12_video_enc_av1] Parsing driver post encode "
1786 "values...D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES_FLAG_LOOP_FILTER_DELTA\n");
1787 pic_header->delta_lf_params = pParsedPostEncodeValues->LoopFilterDelta;
1788
1789 debug_printf("Post encode delta_lf_params.DeltaLFMulti: %" PRIu64 "\n", pic_header->delta_lf_params.DeltaLFMulti);
1790 debug_printf("Post encode delta_lf_params.DeltaLFPresent: %" PRIu64 "\n",
1791 pic_header->delta_lf_params.DeltaLFPresent);
1792 debug_printf("Post encode delta_lf_params.DeltaLFRes: %" PRIu64 "\n", pic_header->delta_lf_params.DeltaLFRes);
1793 }
1794
1795 {
1796 debug_printf("[d3d12_video_enc_av1] Parsing driver post encode "
1797 "values...D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES_FLAG_LOOP_FILTER\n");
1798 pic_header->loop_filter_params = pParsedPostEncodeValues->LoopFilter;
1799
1800 debug_printf("Post encode loop_filter_params.LoopFilterDeltaEnabled: %" PRIu64 "\n",
1801 pic_header->loop_filter_params.LoopFilterDeltaEnabled);
1802 debug_printf("Post encode loop_filter_params.LoopFilterLevel[0]: %" PRIu64 "\n",
1803 pic_header->loop_filter_params.LoopFilterLevel[0]);
1804 debug_printf("Post encode loop_filter_params.LoopFilterLevel[1]: %" PRIu64 "\n",
1805 pic_header->loop_filter_params.LoopFilterLevel[1]);
1806 debug_printf("Post encode loop_filter_params.LoopFilterLevelU: %" PRIu64 "\n",
1807 pic_header->loop_filter_params.LoopFilterLevelU);
1808 debug_printf("Post encode loop_filter_params.LoopFilterLevelV: %" PRIu64 "\n",
1809 pic_header->loop_filter_params.LoopFilterLevelV);
1810 debug_printf("Post encode loop_filter_params.LoopFilterSharpnessLevel: %" PRIu64 "\n",
1811 pic_header->loop_filter_params.LoopFilterSharpnessLevel);
1812 debug_printf("Post encode loop_filter_params.ModeDeltas[0]: %" PRIu64 "\n",
1813 pic_header->loop_filter_params.ModeDeltas[0]);
1814 debug_printf("Post encode loop_filter_params.ModeDeltas[1]: %" PRIu64 "\n",
1815 pic_header->loop_filter_params.ModeDeltas[1]);
1816 for (uint8_t i = 0; i < 8; i++) {
1817 debug_printf("Post encode loop_filter_params.RefDeltas[%d]: %" PRIu64 "\n",
1818 i,
1819 pic_header->loop_filter_params.RefDeltas[i]);
1820 }
1821 debug_printf("Post encode loop_filter_params.UpdateModeDelta: %" PRIu64 "\n",
1822 pic_header->loop_filter_params.UpdateModeDelta);
1823 debug_printf("Post encode loop_filter_params.UpdateRefDelta: %" PRIu64 "\n",
1824 pic_header->loop_filter_params.UpdateRefDelta);
1825 }
1826
1827 {
1828 debug_printf("[d3d12_video_enc_av1] Parsing driver post encode "
1829 "values...D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES_FLAG_CDEF_DATA\n");
1830 pic_header->cdef_params = pParsedPostEncodeValues->CDEF;
1831
1832 debug_printf("Post encode cdef_params.CdefBits: %" PRIu64 "\n", pic_header->cdef_params.CdefBits);
1833
1834 debug_printf("Post encode cdef_params.CdefDampingMinus3: %" PRIu64 "\n",
1835 pic_header->cdef_params.CdefDampingMinus3);
1836
1837 for (uint8_t i = 0; i < 8; i++) {
1838 debug_printf("Post encode cdef_params.CdefYPriStrength[%d]: %" PRIu64 "\n",
1839 i,
1840 pic_header->cdef_params.CdefYPriStrength[i]);
1841
1842 debug_printf("Post encode cdef_params.CdefUVPriStrength[%d]: %" PRIu64 "\n",
1843 i,
1844 pic_header->cdef_params.CdefUVPriStrength[i]);
1845
1846 debug_printf("Post encode cdef_params.CdefYSecStrength[%d]: %" PRIu64 "\n",
1847 i,
1848 pic_header->cdef_params.CdefYSecStrength[i]);
1849
1850 debug_printf("Post encode cdef_params.CdefUVSecStrength[%d]: %" PRIu64 "\n",
1851 i,
1852 pic_header->cdef_params.CdefUVSecStrength[i]);
1853 }
1854 }
1855
1856 {
1857 debug_printf("[d3d12_video_enc_av1] Parsing driver post encode "
1858 "values...D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES_FLAG_COMPOUND_PREDICTION_MODE\n");
1859 pic_header->reference_select = (pParsedPostEncodeValues->CompoundPredictionType ==
1860 D3D12_VIDEO_ENCODER_AV1_COMP_PREDICTION_TYPE_SINGLE_REFERENCE) ?
1861 0 :
1862 1;
1863 debug_printf("Post encode reference_select: %" PRIu32 "\n", pic_header->reference_select);
1864 }
1865
1866 // if ((pevFlags & D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES_FLAG_CONTEXT_UPDATE_TILE_ID) != 0)
1867 // We just copy the whole structure, the driver must copy it even if the pev flag is not set
1868 pic_header->tile_info.tile_partition = *pParsedTilePartitions;
1869
1870 {
1871 debug_printf("[d3d12_video_enc_av1] Parsing driver post encode "
1872 "values...D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES_FLAG_PRIMARY_REF_FRAME\n");
1873 pic_header->primary_ref_frame = static_cast<uint32_t>(pParsedPostEncodeValues->PrimaryRefFrame);
1874 debug_printf("Post encode primary_ref_frame: %" PRIu32 "\n", pic_header->primary_ref_frame);
1875 }
1876
1877 debug_printf("Post encode tile_info.tile_partition.ContextUpdateTileId: %" PRIu64 "\n",
1878 pic_header->tile_info.tile_partition.ContextUpdateTileId);
1879 debug_printf("Post encode tile_info.tile_partition.ColCount: %" PRIu64 "\n",
1880 pic_header->tile_info.tile_partition.ColCount);
1881 debug_printf("Post encode tile_info.tile_partition.RowCount: %" PRIu64 "\n",
1882 pic_header->tile_info.tile_partition.RowCount);
1883
1884 assert(pic_header->tile_info.tile_partition.ColCount < 64);
1885 for (uint8_t i = 0; i < pic_header->tile_info.tile_partition.ColCount; i++) {
1886 debug_printf("Post encode tile_info.tile_partition.ColWidths[%d]: %" PRIu64 "\n",
1887 i,
1888 pic_header->tile_info.tile_partition.ColWidths[i]);
1889 }
1890
1891 assert(pic_header->tile_info.tile_partition.RowCount < 64);
1892 for (uint8_t i = 0; i < pic_header->tile_info.tile_partition.RowCount; i++) {
1893 debug_printf("Post encode tile_info.tile_partition.RowHeights[%d]: %" PRIu64 "\n",
1894 i,
1895 pic_header->tile_info.tile_partition.RowHeights[i]);
1896 }
1897
1898 pic_header->show_existing_frame = 0;
1899 pic_header->frame_to_show_map_idx = 0;
1900
1901 // pic_header->display_frame_id; // frame_id_numbers_present_flag coded in bitstream by default as 0
1902
1903 pic_header->frame_type = associatedMetadata.m_associatedEncodeConfig.m_encoderPicParamsDesc.m_AV1PicData.FrameType;
1904 {
1905 UINT EncodeOrderInGop =
1906 (associatedMetadata.m_associatedEncodeConfig.m_encoderPicParamsDesc.m_AV1PicData.PictureIndex %
1907 associatedMetadata.m_associatedEncodeConfig.m_encoderGOPConfigDesc.m_AV1SequenceStructure.IntraDistance);
1908
1909 UINT ShowOrderInGop =
1910 (associatedMetadata.m_associatedEncodeConfig.m_encoderPicParamsDesc.m_AV1PicData.OrderHint %
1911 associatedMetadata.m_associatedEncodeConfig.m_encoderGOPConfigDesc.m_AV1SequenceStructure.IntraDistance);
1912
1913 pic_header->show_frame = (ShowOrderInGop <= EncodeOrderInGop);
1914 }
1915
1916 pic_header->showable_frame = // this will always be showable for P/B frames, even when using show_frame for B
1917 // frame playback reordering
1918 associatedMetadata.m_associatedEncodeConfig.m_encoderPicParamsDesc.m_AV1PicData.FrameType !=
1919 D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_KEY_FRAME;
1920 pic_header->error_resilient_mode =
1921 ((associatedMetadata.m_associatedEncodeConfig.m_encoderPicParamsDesc.m_AV1PicData.Flags &
1922 D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_ENABLE_ERROR_RESILIENT_MODE) != 0);
1923 pic_header->disable_cdf_update =
1924 ((associatedMetadata.m_associatedEncodeConfig.m_encoderPicParamsDesc.m_AV1PicData.Flags &
1925 D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_DISABLE_CDF_UPDATE) != 0);
1926
1927 pic_header->allow_screen_content_tools =
1928 ((associatedMetadata.m_associatedEncodeConfig.m_encoderPicParamsDesc.m_AV1PicData.Flags &
1929 D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_ENABLE_PALETTE_ENCODING) != 0);
1930 pic_header->force_integer_mv =
1931 ((associatedMetadata.m_associatedEncodeConfig.m_encoderPicParamsDesc.m_AV1PicData.Flags &
1932 D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_FORCE_INTEGER_MOTION_VECTORS) != 0);
1933
1934 // frame_size_override_flag is not coded + default as 1 for SWITCH_FRAME and explicitly coded otherwise
1935 if (pic_header->frame_type == D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_SWITCH_FRAME)
1936 pic_header->frame_size_override_flag = 1; // As per AV1 codec spec
1937 else
1938 pic_header->frame_size_override_flag = 0; // Set as default as 0 when explicitly coded
1939
1940 pic_header->order_hint = associatedMetadata.m_associatedEncodeConfig.m_encoderPicParamsDesc.m_AV1PicData.OrderHint;
1941
1942 pic_header->refresh_frame_flags =
1943 associatedMetadata.m_associatedEncodeConfig.m_encoderPicParamsDesc.m_AV1PicData.RefreshFrameFlags;
1944
1945 // frame_size (comes from input texture size)
1946 pic_header->FrameWidth = associatedMetadata.m_associatedEncodeConfig.m_currentResolution.Width;
1947 pic_header->UpscaledWidth = associatedMetadata.m_associatedEncodeConfig.m_currentResolution.Width;
1948 pic_header->FrameHeight = associatedMetadata.m_associatedEncodeConfig.m_currentResolution.Height;
1949
1950 // render_size (comes from AV1 pipe picparams pic)
1951 pic_header->RenderWidth = associatedMetadata.m_associatedEncodeConfig.m_FrameCroppingCodecConfig.right;
1952 pic_header->RenderHeight = associatedMetadata.m_associatedEncodeConfig.m_FrameCroppingCodecConfig.bottom;
1953
1954 bool use_128x128_superblock =
1955 ((associatedMetadata.m_associatedEncodeConfig.m_encoderCodecSpecificConfigDesc.m_AV1Config.FeatureFlags &
1956 D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_128x128_SUPERBLOCK) != 0) ?
1957 1 :
1958 0;
1959 unsigned MiCols = 2 * ((pic_header->FrameWidth + 7) >> 3);
1960 unsigned MiRows = 2 * ((pic_header->FrameHeight + 7) >> 3);
1961 pic_header->frame_width_sb = use_128x128_superblock ? ((MiCols + 31) >> 5) : ((MiCols + 15) >> 4);
1962 pic_header->frame_height_sb = use_128x128_superblock ? ((MiRows + 31) >> 5) : ((MiRows + 15) >> 4);
1963
1964 pic_header->use_superres = ((associatedMetadata.m_associatedEncodeConfig.m_encoderPicParamsDesc.m_AV1PicData.Flags &
1965 D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_USE_SUPER_RESOLUTION) != 0);
1966 pic_header->SuperresDenom =
1967 associatedMetadata.m_associatedEncodeConfig.m_encoderPicParamsDesc.m_AV1PicData.SuperResDenominator;
1968
1969 pic_header->allow_intrabc = ((associatedMetadata.m_associatedEncodeConfig.m_encoderPicParamsDesc.m_AV1PicData.Flags &
1970 D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_ALLOW_INTRA_BLOCK_COPY) != 0);
1971
1972 for (unsigned i = 0; i < ARRAY_SIZE(associatedMetadata.m_associatedEncodeConfig.m_encoderPicParamsDesc.m_AV1PicData
1973 .ReferenceFramesReconPictureDescriptors);
1974 i++) {
1975 pic_header->ref_order_hint[i] = associatedMetadata.m_associatedEncodeConfig.m_encoderPicParamsDesc.m_AV1PicData
1976 .ReferenceFramesReconPictureDescriptors[i]
1977 .OrderHint;
1978 }
1979
1980 for (uint8_t i = 0; i < ARRAY_SIZE(pParsedPostEncodeValues->ReferenceIndices); i++)
1981 pic_header->ref_frame_idx[i] = pParsedPostEncodeValues->ReferenceIndices[i];
1982
1983 pic_header->allow_high_precision_mv =
1984 ((associatedMetadata.m_associatedEncodeConfig.m_encoderPicParamsDesc.m_AV1PicData.Flags &
1985 D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_ALLOW_HIGH_PRECISION_MV) != 0);
1986 pic_header->interpolation_filter =
1987 associatedMetadata.m_associatedEncodeConfig.m_encoderPicParamsDesc.m_AV1PicData.InterpolationFilter;
1988 pic_header->is_motion_mode_switchable =
1989 ((associatedMetadata.m_associatedEncodeConfig.m_encoderPicParamsDesc.m_AV1PicData.Flags &
1990 D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_MOTION_MODE_SWITCHABLE) != 0);
1991 pic_header->use_ref_frame_mvs =
1992 ((associatedMetadata.m_associatedEncodeConfig.m_encoderPicParamsDesc.m_AV1PicData.Flags &
1993 D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_FRAME_REFERENCE_MOTION_VECTORS) != 0);
1994 pic_header->disable_frame_end_update_cdf =
1995 ((associatedMetadata.m_associatedEncodeConfig.m_encoderPicParamsDesc.m_AV1PicData.Flags &
1996 D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_DISABLE_FRAME_END_UPDATE_CDF) != 0);
1997
1998 pic_header->tile_info.tile_mode = associatedMetadata.m_associatedEncodeConfig.m_encoderSliceConfigMode;
1999 pic_header->tile_info.tile_support_caps =
2000 associatedMetadata.m_associatedEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1TileCaps;
2001
2002 pic_header->tile_info.uniform_tile_spacing_flag = 0;
2003 if ((pic_header->tile_info.tile_mode == D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_GRID_PARTITION) ||
2004 (pic_header->tile_info.tile_mode == D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_FULL_FRAME))
2005 pic_header->tile_info.uniform_tile_spacing_flag = 1;
2006 else if (pic_header->tile_info.tile_mode ==
2007 D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_CONFIGURABLE_GRID_PARTITION)
2008 pic_header->tile_info.uniform_tile_spacing_flag = 0;
2009 else
2010 assert(false); // Unknown pic_header->tile_info.tile_mode for AV1
2011
2012 // lr_params
2013 for (uint32_t i = 0; i < 3; i++)
2014 pic_header->lr_params.lr_type[i] = associatedMetadata.m_associatedEncodeConfig.m_encoderPicParamsDesc.m_AV1PicData
2015 .FrameRestorationConfig.FrameRestorationType[i];
2016 bool lr_enabled =
2017 pic_header->lr_params.lr_type[0] || pic_header->lr_params.lr_type[1] || pic_header->lr_params.lr_type[2];
2018 if (lr_enabled) {
2019 uint8_t luma_shift_total = log2(d3d12_video_encoder_looprestorationsize_d3d12_to_uint_av1(
2020 associatedMetadata.m_associatedEncodeConfig.m_encoderPicParamsDesc.m_AV1PicData
2021 .FrameRestorationConfig.LoopRestorationPixelSize[0])) -
2022 6;
2023 pic_header->lr_params.lr_unit_shift = (luma_shift_total > 0) ? 1 : 0;
2024 pic_header->lr_params.lr_unit_extra_shift = (luma_shift_total > 1) ? 1 : 0;
2025 assert(associatedMetadata.m_associatedEncodeConfig.m_encoderPicParamsDesc.m_AV1PicData.FrameRestorationConfig
2026 .LoopRestorationPixelSize[1] == associatedMetadata.m_associatedEncodeConfig.m_encoderPicParamsDesc
2027 .m_AV1PicData.FrameRestorationConfig.LoopRestorationPixelSize[2]);
2028
2029 if (associatedMetadata.m_associatedEncodeConfig.m_encoderPicParamsDesc.m_AV1PicData.FrameRestorationConfig
2030 .LoopRestorationPixelSize[1]) {
2031 pic_header->lr_params.lr_uv_shift = log2(d3d12_video_encoder_looprestorationsize_d3d12_to_uint_av1(
2032 associatedMetadata.m_associatedEncodeConfig.m_encoderPicParamsDesc
2033 .m_AV1PicData.FrameRestorationConfig.LoopRestorationPixelSize[1])) +
2034 6 + luma_shift_total;
2035 } else {
2036 pic_header->lr_params.lr_uv_shift = 0;
2037 }
2038 }
2039
2040 pic_header->TxMode = associatedMetadata.m_associatedEncodeConfig.m_encoderPicParamsDesc.m_AV1PicData.TxMode;
2041 pic_header->skip_mode_present =
2042 ((associatedMetadata.m_associatedEncodeConfig.m_encoderPicParamsDesc.m_AV1PicData.Flags &
2043 D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_ENABLE_SKIP_MODE) != 0);
2044 pic_header->allow_warped_motion =
2045 ((associatedMetadata.m_associatedEncodeConfig.m_encoderPicParamsDesc.m_AV1PicData.Flags &
2046 D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_ENABLE_WARPED_MOTION) != 0);
2047 pic_header->reduced_tx_set =
2048 ((associatedMetadata.m_associatedEncodeConfig.m_encoderPicParamsDesc.m_AV1PicData.Flags &
2049 D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_REDUCED_TX_SET) != 0);
2050 // pic_header->frame_refs_short_signaling; // coded in bitstream by default as 0
2051 }
2052
2053 D3D12_VIDEO_ENCODER_AV1_RESTORATION_TILESIZE
d3d12_video_encoder_looprestorationsize_uint_to_d3d12_av1(uint32_t pixel_size)2054 d3d12_video_encoder_looprestorationsize_uint_to_d3d12_av1(uint32_t pixel_size)
2055 {
2056 switch (pixel_size) {
2057 case 32:
2058 {
2059 return D3D12_VIDEO_ENCODER_AV1_RESTORATION_TILESIZE_32x32;
2060 } break;
2061 case 64:
2062 {
2063 return D3D12_VIDEO_ENCODER_AV1_RESTORATION_TILESIZE_64x64;
2064 } break;
2065 case 128:
2066 {
2067 return D3D12_VIDEO_ENCODER_AV1_RESTORATION_TILESIZE_128x128;
2068 } break;
2069 case 256:
2070 {
2071 return D3D12_VIDEO_ENCODER_AV1_RESTORATION_TILESIZE_256x256;
2072 } break;
2073 default:
2074 {
2075 unreachable("Unsupported D3D12_VIDEO_ENCODER_AV1_PROFILE");
2076 } break;
2077 }
2078 }
2079
2080 unsigned
d3d12_video_encoder_looprestorationsize_d3d12_to_uint_av1(D3D12_VIDEO_ENCODER_AV1_RESTORATION_TILESIZE d3d12_type)2081 d3d12_video_encoder_looprestorationsize_d3d12_to_uint_av1(D3D12_VIDEO_ENCODER_AV1_RESTORATION_TILESIZE d3d12_type)
2082 {
2083 switch (d3d12_type) {
2084 case D3D12_VIDEO_ENCODER_AV1_RESTORATION_TILESIZE_32x32:
2085 {
2086 return 32;
2087 } break;
2088 case D3D12_VIDEO_ENCODER_AV1_RESTORATION_TILESIZE_64x64:
2089 {
2090 return 64;
2091 } break;
2092 case D3D12_VIDEO_ENCODER_AV1_RESTORATION_TILESIZE_128x128:
2093 {
2094 return 128;
2095 } break;
2096 case D3D12_VIDEO_ENCODER_AV1_RESTORATION_TILESIZE_256x256:
2097 {
2098 return 256;
2099 } break;
2100 default:
2101 {
2102 unreachable("Unsupported D3D12_VIDEO_ENCODER_AV1_PROFILE");
2103 } break;
2104 }
2105 }
2106
2107 /*
2108 * Called at get_feedback time FOR A PREVIOUSLY RECORDED AND EXECUTED FRAME
2109 */
2110 unsigned
d3d12_video_encoder_build_post_encode_codec_bitstream_av1(struct d3d12_video_encoder * pD3D12Enc,uint64_t associated_fence_value,EncodedBitstreamResolvedMetadata & associatedMetadata)2111 d3d12_video_encoder_build_post_encode_codec_bitstream_av1(struct d3d12_video_encoder *pD3D12Enc,
2112 uint64_t associated_fence_value,
2113 EncodedBitstreamResolvedMetadata &associatedMetadata)
2114 {
2115 // Parse the AV1 resolved metadata
2116
2117 ID3D12Resource *pResolvedMetadataBuffer = associatedMetadata.spBuffer.Get();
2118 uint64_t resourceMetadataSize = associatedMetadata.bufferSize;
2119
2120 struct d3d12_screen *pD3D12Screen = (struct d3d12_screen *) pD3D12Enc->m_pD3D12Screen;
2121 pipe_resource *pPipeResolvedMetadataBuffer =
2122 d3d12_resource_from_resource(&pD3D12Screen->base, pResolvedMetadataBuffer);
2123 assert(resourceMetadataSize < INT_MAX);
2124 struct pipe_box box = {
2125 0, // x
2126 0, // y
2127 0, // z
2128 static_cast<int>(resourceMetadataSize), // width
2129 1, // height
2130 1 // depth
2131 };
2132 struct pipe_transfer *mapTransferMetadata;
2133 uint8_t *pMetadataBufferSrc =
2134 reinterpret_cast<uint8_t *>(pD3D12Enc->base.context->buffer_map(pD3D12Enc->base.context,
2135 pPipeResolvedMetadataBuffer,
2136 0,
2137 PIPE_MAP_READ,
2138 &box,
2139 &mapTransferMetadata));
2140
2141 debug_printf("[d3d12_video_enc_av1] Parsing driver resolved encode metadata...\n");
2142
2143 D3D12_VIDEO_ENCODER_OUTPUT_METADATA *pParsedMetadata =
2144 reinterpret_cast<D3D12_VIDEO_ENCODER_OUTPUT_METADATA *>(pMetadataBufferSrc);
2145 pMetadataBufferSrc += sizeof(D3D12_VIDEO_ENCODER_OUTPUT_METADATA);
2146
2147 D3D12_VIDEO_ENCODER_FRAME_SUBREGION_METADATA *pFrameSubregionMetadata =
2148 reinterpret_cast<D3D12_VIDEO_ENCODER_FRAME_SUBREGION_METADATA *>(pMetadataBufferSrc);
2149 pMetadataBufferSrc +=
2150 (sizeof(D3D12_VIDEO_ENCODER_FRAME_SUBREGION_METADATA) * pParsedMetadata->WrittenSubregionsCount);
2151
2152 D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_TILES *pParsedTilePartitions =
2153 reinterpret_cast<D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_TILES *>(pMetadataBufferSrc);
2154 pMetadataBufferSrc += sizeof(D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_TILES);
2155
2156 D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES *pParsedPostEncodeValues =
2157 reinterpret_cast<D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES *>(pMetadataBufferSrc);
2158 pMetadataBufferSrc += sizeof(D3D12_VIDEO_ENCODER_AV1_POST_ENCODE_VALUES);
2159
2160 debug_printf("[d3d12_video_enc_av1] D3D12_VIDEO_ENCODER_OUTPUT_METADATA.EncodeErrorFlags: %" PRIx64 " \n",
2161 pParsedMetadata->EncodeErrorFlags);
2162 debug_printf("[d3d12_video_enc_av1] D3D12_VIDEO_ENCODER_OUTPUT_METADATA.EncodeStats.AverageQP: %" PRIu64 " \n",
2163 pParsedMetadata->EncodeStats.AverageQP);
2164 debug_printf("[d3d12_video_enc_av1] D3D12_VIDEO_ENCODER_OUTPUT_METADATA.EncodeStats.IntraCodingUnitsCount: %" PRIu64
2165 " \n",
2166 pParsedMetadata->EncodeStats.IntraCodingUnitsCount);
2167 debug_printf("[d3d12_video_enc_av1] D3D12_VIDEO_ENCODER_OUTPUT_METADATA.EncodeStats.InterCodingUnitsCount: %" PRIu64
2168 " \n",
2169 pParsedMetadata->EncodeStats.InterCodingUnitsCount);
2170 debug_printf("[d3d12_video_enc_av1] D3D12_VIDEO_ENCODER_OUTPUT_METADATA.EncodeStats.SkipCodingUnitsCount: %" PRIu64
2171 " \n",
2172 pParsedMetadata->EncodeStats.SkipCodingUnitsCount);
2173 debug_printf("[d3d12_video_enc_av1] "
2174 "D3D12_VIDEO_ENCODER_OUTPUT_METADATA.EncodeStats.AverageMotionEstimationXDirection: %" PRIu64 " \n",
2175 pParsedMetadata->EncodeStats.AverageMotionEstimationXDirection);
2176 debug_printf("[d3d12_video_enc_av1] "
2177 "D3D12_VIDEO_ENCODER_OUTPUT_METADATA.EncodeStats.AverageMotionEstimationYDirection: %" PRIu64 " \n",
2178 pParsedMetadata->EncodeStats.AverageMotionEstimationYDirection);
2179 debug_printf("[d3d12_video_enc_av1] D3D12_VIDEO_ENCODER_OUTPUT_METADATA.EncodedBitstreamWrittenBytesCount: %" PRIu64
2180 " \n",
2181 pParsedMetadata->EncodedBitstreamWrittenBytesCount);
2182 debug_printf("[d3d12_video_enc_av1] D3D12_VIDEO_ENCODER_OUTPUT_METADATA.WrittenSubregionsCount: %" PRIu64 " \n",
2183 pParsedMetadata->WrittenSubregionsCount);
2184
2185 for (uint8_t i = 0; i < pParsedMetadata->WrittenSubregionsCount; i++) {
2186 debug_printf("[d3d12_video_enc_av1] D3D12_VIDEO_ENCODER_FRAME_SUBREGION_METADATA[%d].bHeaderSize: %" PRIu64 " \n",
2187 i,
2188 pFrameSubregionMetadata[i].bHeaderSize);
2189 debug_printf("[d3d12_video_enc_av1] D3D12_VIDEO_ENCODER_FRAME_SUBREGION_METADATA[%d].bStartOffset: %" PRIu64
2190 " \n",
2191 i,
2192 pFrameSubregionMetadata[i].bStartOffset);
2193 debug_printf("[d3d12_video_enc_av1] D3D12_VIDEO_ENCODER_FRAME_SUBREGION_METADATA[%d].bSize: %" PRIu64 " \n",
2194 i,
2195 pFrameSubregionMetadata[i].bSize);
2196 }
2197
2198 if (pParsedMetadata->EncodeErrorFlags != D3D12_VIDEO_ENCODER_ENCODE_ERROR_FLAG_NO_ERROR) {
2199 debug_printf("[d3d12_video_enc_av1] Encode GPU command for fence %" PRIu64 " failed - EncodeErrorFlags: %" PRIu64
2200 "\n",
2201 associated_fence_value,
2202 pParsedMetadata->EncodeErrorFlags);
2203 assert(false);
2204 return 0;
2205 }
2206
2207 if (pParsedMetadata->EncodedBitstreamWrittenBytesCount == 0u) {
2208 debug_printf("[d3d12_video_enc_av1] Encode GPU command for fence %" PRIu64
2209 " failed - EncodedBitstreamWrittenBytesCount: 0\n",
2210 associated_fence_value);
2211 assert(false);
2212 return 0;
2213 }
2214
2215 // Create headers
2216
2217 av1_seq_header_t seqHdr = {};
2218 fill_av1_seq_header(associatedMetadata, &seqHdr);
2219 av1_pic_header_t picHdr = {};
2220 fill_av1_pic_header(associatedMetadata, &picHdr, &seqHdr, pParsedPostEncodeValues, pParsedTilePartitions);
2221
2222 bool bNeedSeqUpdate = false;
2223 bool diff_uv_delta_from_pev = (picHdr.quantization_params.VDCDeltaQ != picHdr.quantization_params.UDCDeltaQ) ||
2224 (picHdr.quantization_params.VACDeltaQ != picHdr.quantization_params.UACDeltaQ);
2225 debug_printf("[Calculated] Post encode diff_uv_delta_from_pev: %d\n", diff_uv_delta_from_pev);
2226
2227 // Make sure the Seq header allows diff_uv_delta from pev
2228 if (diff_uv_delta_from_pev && !seqHdr.color_config.separate_uv_delta_q) {
2229 seqHdr.color_config.separate_uv_delta_q = 1;
2230 bNeedSeqUpdate = true;
2231 }
2232
2233 d3d12_video_bitstream_builder_av1 *pAV1BitstreamBuilder =
2234 static_cast<d3d12_video_bitstream_builder_av1 *>(pD3D12Enc->m_upBitstreamBuilder.get());
2235 assert(pAV1BitstreamBuilder);
2236
2237 associatedMetadata.pWrittenCodecUnitsSizes.clear();
2238
2239 size_t writtenTemporalDelimBytes = 0;
2240 if (picHdr.show_frame && associatedMetadata.m_CodecSpecificData.AV1HeadersInfo.temporal_delim_rendered) {
2241 pAV1BitstreamBuilder->write_temporal_delimiter_obu(
2242 pD3D12Enc->m_BitstreamHeadersBuffer,
2243 pD3D12Enc->m_BitstreamHeadersBuffer.begin(), // placingPositionStart
2244 writtenTemporalDelimBytes // Bytes Written AFTER placingPositionStart arg above
2245 );
2246 assert(pD3D12Enc->m_BitstreamHeadersBuffer.size() == writtenTemporalDelimBytes);
2247 debug_printf("Written OBU_TEMPORAL_DELIMITER bytes: %" PRIu64 "\n", static_cast<uint64_t>(writtenTemporalDelimBytes));
2248 associatedMetadata.pWrittenCodecUnitsSizes.push_back(writtenTemporalDelimBytes);
2249 }
2250
2251 size_t writtenSequenceBytes = 0;
2252 bool isFirstFrame = (associated_fence_value == 1);
2253
2254 // on first frame or on resolution change or if we changed seq hdr values with post encode values
2255 bool writeNewSeqHeader = isFirstFrame || bNeedSeqUpdate ||
2256 ((associatedMetadata.m_associatedEncodeConfig.m_seqFlags &
2257 D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_FLAG_RESOLUTION_CHANGE) != 0);
2258
2259 if (writeNewSeqHeader) {
2260 pAV1BitstreamBuilder->write_sequence_header(
2261 &seqHdr,
2262 pD3D12Enc->m_BitstreamHeadersBuffer,
2263 pD3D12Enc->m_BitstreamHeadersBuffer.begin() + writtenTemporalDelimBytes, // placingPositionStart
2264 writtenSequenceBytes // Bytes Written AFTER placingPositionStart arg above
2265 );
2266 associatedMetadata.pWrittenCodecUnitsSizes.push_back(writtenSequenceBytes);
2267 assert(pD3D12Enc->m_BitstreamHeadersBuffer.size() == (writtenSequenceBytes + writtenTemporalDelimBytes));
2268 debug_printf("Written OBU_SEQUENCE_HEADER bytes: %" PRIu64 "\n", static_cast<uint64_t>(writtenSequenceBytes));
2269 }
2270
2271 // Only supported bitstream format is with obu_size for now.
2272 assert(associatedMetadata.m_CodecSpecificData.AV1HeadersInfo.obu_has_size_field);
2273
2274 size_t writtenFrameBytes = 0;
2275 size_t writtenTileBytes = 0;
2276
2277 pipe_resource *src_driver_bitstream =
2278 d3d12_resource_from_resource(&pD3D12Enc->m_pD3D12Screen->base, associatedMetadata.spStagingBitstream.Get());
2279 assert(src_driver_bitstream);
2280
2281 size_t comp_bitstream_offset = 0;
2282 if (associatedMetadata.m_CodecSpecificData.AV1HeadersInfo.enable_frame_obu) {
2283 // FRAME_OBU combined frame and tile data case
2284
2285 assert(associatedMetadata.m_associatedEncodeConfig.m_encoderSliceConfigDesc.m_TilesConfig_AV1.TilesGroupsCount ==
2286 1);
2287
2288 // write_frame_header writes OBU_FRAME except tile_obu_group, but included obu_size for tile_group_obu as
2289 // calculated below
2290 size_t tile_group_obu_size = 0;
2291 size_t decode_tile_elements_size = 0;
2292 pAV1BitstreamBuilder->calculate_tile_group_obu_size(
2293 pParsedMetadata,
2294 pFrameSubregionMetadata,
2295 associatedMetadata.m_associatedEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1TileCaps
2296 .TileSizeBytesMinus1 +
2297 1,
2298 associatedMetadata.m_associatedEncodeConfig.m_encoderSliceConfigDesc.m_TilesConfig_AV1.TilesPartition,
2299 associatedMetadata.m_associatedEncodeConfig.m_encoderSliceConfigDesc.m_TilesConfig_AV1.TilesGroups[0],
2300 tile_group_obu_size,
2301 decode_tile_elements_size);
2302
2303 pAV1BitstreamBuilder->write_frame_header(
2304 &seqHdr,
2305 &picHdr,
2306 OBU_FRAME,
2307 tile_group_obu_size, // We need it to code obu_size of OBU_FRAME open_bitstream_unit()
2308 pD3D12Enc->m_BitstreamHeadersBuffer,
2309 pD3D12Enc->m_BitstreamHeadersBuffer.begin() + writtenSequenceBytes +
2310 writtenTemporalDelimBytes, // placingPositionStart
2311 writtenFrameBytes // Bytes Written AFTER placingPositionStart arg above
2312 );
2313
2314 debug_printf("Written OBU_FRAME bytes: %" PRIu64 "\n", static_cast<uint64_t>(writtenFrameBytes));
2315 associatedMetadata.pWrittenCodecUnitsSizes.push_back(writtenFrameBytes);
2316
2317 assert(pD3D12Enc->m_BitstreamHeadersBuffer.size() ==
2318 (writtenSequenceBytes + writtenTemporalDelimBytes + writtenFrameBytes));
2319
2320 debug_printf("Uploading %" PRIu64
2321 " bytes from OBU sequence and/or picture headers to comp_bit_destination %p at offset 0\n",
2322 static_cast<uint64_t>(pD3D12Enc->m_BitstreamHeadersBuffer.size()),
2323 associatedMetadata.comp_bit_destination);
2324
2325 // Upload headers to the finalized compressed bitstream buffer
2326 // Note: The buffer_subdata is queued in pD3D12Enc->base.context but doesn't execute immediately
2327 pD3D12Enc->base.context->buffer_subdata(pD3D12Enc->base.context, // context
2328 associatedMetadata.comp_bit_destination, // comp. bitstream
2329 PIPE_MAP_WRITE, // usage PIPE_MAP_x
2330 0, // offset
2331 pD3D12Enc->m_BitstreamHeadersBuffer.size(),
2332 pD3D12Enc->m_BitstreamHeadersBuffer.data());
2333
2334 comp_bitstream_offset = pD3D12Enc->m_BitstreamHeadersBuffer.size();
2335 size_t written_bytes_to_staging_bitstream_buffer = 0;
2336
2337 upload_tile_group_obu(
2338 pD3D12Enc,
2339 tile_group_obu_size,
2340 decode_tile_elements_size,
2341 associatedMetadata.m_StagingBitstreamConstruction,
2342 0, // staging_bitstream_buffer_offset,
2343 src_driver_bitstream,
2344 associatedMetadata.comp_bit_destination,
2345 comp_bitstream_offset,
2346 pFrameSubregionMetadata,
2347 associatedMetadata.m_associatedEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1TileCaps
2348 .TileSizeBytesMinus1 +
2349 1,
2350 associatedMetadata.m_associatedEncodeConfig.m_encoderSliceConfigDesc.m_TilesConfig_AV1.TilesPartition,
2351 associatedMetadata.m_associatedEncodeConfig.m_encoderSliceConfigDesc.m_TilesConfig_AV1.TilesGroups[0],
2352 written_bytes_to_staging_bitstream_buffer,
2353 associatedMetadata.pWrittenCodecUnitsSizes);
2354
2355 writtenTileBytes += tile_group_obu_size;
2356 comp_bitstream_offset += writtenTileBytes;
2357
2358 // Flush batch with upload work and wait on this CPU thread for GPU work completion
2359 {
2360 struct pipe_fence_handle *pUploadGPUCompletionFence = NULL;
2361 pD3D12Enc->base.context->flush(pD3D12Enc->base.context,
2362 &pUploadGPUCompletionFence,
2363 PIPE_FLUSH_ASYNC | PIPE_FLUSH_HINT_FINISH);
2364 assert(pUploadGPUCompletionFence);
2365 debug_printf(
2366 "[d3d12_video_encoder] d3d12_video_encoder_build_post_encode_codec_bitstream_av1 - Waiting on GPU "
2367 "completion fence for "
2368 " uploading finalized codec headers to compressed bitstream.\n");
2369
2370 pD3D12Enc->m_pD3D12Screen->base.fence_finish(&pD3D12Enc->m_pD3D12Screen->base,
2371 NULL,
2372 pUploadGPUCompletionFence,
2373 OS_TIMEOUT_INFINITE);
2374 pD3D12Enc->m_pD3D12Screen->base.fence_reference(&pD3D12Enc->m_pD3D12Screen->base,
2375 &pUploadGPUCompletionFence,
2376 NULL);
2377 }
2378 } else {
2379 // FRAME_HEADER_OBU + OBU_TILE_GROUP concatenated case
2380
2381 // Build open_bitstream_unit for OBU_FRAME_HEADER
2382 pAV1BitstreamBuilder->write_frame_header(&seqHdr,
2383 &picHdr,
2384 OBU_FRAME_HEADER,
2385 0, // no tile_obu_group in OBU_FRAME_HEADER
2386 pD3D12Enc->m_BitstreamHeadersBuffer,
2387 pD3D12Enc->m_BitstreamHeadersBuffer.begin() + writtenSequenceBytes +
2388 writtenTemporalDelimBytes, // placingPositionStart
2389 writtenFrameBytes // Bytes Written AFTER placingPositionStart arg above
2390 );
2391 associatedMetadata.pWrittenCodecUnitsSizes.push_back(writtenFrameBytes);
2392
2393 debug_printf("Written OBU_FRAME_HEADER bytes: %" PRIu64 "\n", static_cast<uint64_t>(writtenFrameBytes));
2394
2395 assert(pD3D12Enc->m_BitstreamHeadersBuffer.size() ==
2396 (writtenSequenceBytes + writtenTemporalDelimBytes + writtenFrameBytes));
2397
2398 debug_printf("Uploading %" PRIu64 " bytes from OBU headers to comp_bit_destination %p at offset 0\n",
2399 static_cast<uint64_t>(pD3D12Enc->m_BitstreamHeadersBuffer.size()),
2400 associatedMetadata.comp_bit_destination);
2401
2402 // Upload headers to the finalized compressed bitstream buffer
2403 // Note: The buffer_subdata is queued in pD3D12Enc->base.context but doesn't execute immediately
2404 pD3D12Enc->base.context->buffer_subdata(pD3D12Enc->base.context, // context
2405 associatedMetadata.comp_bit_destination, // comp. bitstream
2406 PIPE_MAP_WRITE, // usage PIPE_MAP_x
2407 0, // offset
2408 pD3D12Enc->m_BitstreamHeadersBuffer.size(),
2409 pD3D12Enc->m_BitstreamHeadersBuffer.data());
2410
2411 comp_bitstream_offset = pD3D12Enc->m_BitstreamHeadersBuffer.size();
2412 size_t staging_bitstream_buffer_offset = 0;
2413
2414 for (int tg_idx = 0;
2415 tg_idx <
2416 associatedMetadata.m_associatedEncodeConfig.m_encoderSliceConfigDesc.m_TilesConfig_AV1.TilesGroupsCount;
2417 tg_idx++) {
2418 auto ¤tTg =
2419 associatedMetadata.m_associatedEncodeConfig.m_encoderSliceConfigDesc.m_TilesConfig_AV1.TilesGroups[tg_idx];
2420
2421 debug_printf("Uploading tile group %d to comp_bit_destination %p at offset %" PRIu64 "\n",
2422 tg_idx,
2423 associatedMetadata.comp_bit_destination,
2424 static_cast<uint64_t>(comp_bitstream_offset));
2425
2426 size_t tile_group_obu_size = 0;
2427 size_t decode_tile_elements_size = 0;
2428 pAV1BitstreamBuilder->calculate_tile_group_obu_size(
2429 pParsedMetadata,
2430 pFrameSubregionMetadata,
2431 associatedMetadata.m_associatedEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1TileCaps
2432 .TileSizeBytesMinus1 +
2433 1,
2434 associatedMetadata.m_associatedEncodeConfig.m_encoderSliceConfigDesc.m_TilesConfig_AV1.TilesPartition,
2435 currentTg,
2436 tile_group_obu_size,
2437 decode_tile_elements_size);
2438
2439 size_t writtenTileObuPrefixBytes = 0;
2440 pAV1BitstreamBuilder->write_obu_tile_group_header(
2441 tile_group_obu_size, // tile_group_obu() size to pack OBU_TILE_GROUP obu_size element
2442 associatedMetadata.m_StagingBitstreamConstruction, // Source CPU buffer cannot be overwritten until
2443 // GPU upload flush finishes.
2444 associatedMetadata.m_StagingBitstreamConstruction.begin() +
2445 staging_bitstream_buffer_offset, // placingPositionStart
2446 writtenTileObuPrefixBytes); // Bytes Written AFTER placingPositionStart arg above
2447
2448 debug_printf("Written %" PRIu64 " bytes for OBU_TILE_GROUP open_bitstream_unit() prefix with obu_header() and "
2449 "obu_size to staging_bitstream_buffer %p at offset %" PRIu64 "\n",
2450 static_cast<uint64_t>(writtenTileObuPrefixBytes),
2451 associatedMetadata.m_StagingBitstreamConstruction.data(),
2452 static_cast<uint64_t>(staging_bitstream_buffer_offset));
2453
2454 writtenTileBytes += writtenTileObuPrefixBytes;
2455 associatedMetadata.pWrittenCodecUnitsSizes.push_back(writtenTileObuPrefixBytes);
2456
2457 // Note: The buffer_subdata is queued in pD3D12Enc->base.context but doesn't execute immediately
2458 pD3D12Enc->base.context->buffer_subdata(
2459 pD3D12Enc->base.context, // context
2460 associatedMetadata.comp_bit_destination, // comp. bitstream
2461 PIPE_MAP_WRITE, // usage PIPE_MAP_x
2462 comp_bitstream_offset, // offset
2463 writtenTileObuPrefixBytes,
2464 associatedMetadata.m_StagingBitstreamConstruction.data() + staging_bitstream_buffer_offset);
2465
2466 debug_printf("Uploading %" PRIu64 " bytes for OBU_TILE_GROUP open_bitstream_unit() prefix with obu_header() "
2467 "and obu_size: %" PRIu64 " to comp_bit_destination %p at offset %" PRIu64 "\n",
2468 static_cast<uint64_t>(writtenTileObuPrefixBytes),
2469 static_cast<uint64_t>(tile_group_obu_size),
2470 associatedMetadata.comp_bit_destination,
2471 static_cast<uint64_t>(comp_bitstream_offset));
2472
2473 staging_bitstream_buffer_offset += writtenTileObuPrefixBytes;
2474
2475 comp_bitstream_offset += writtenTileObuPrefixBytes;
2476
2477 size_t written_bytes_to_staging_bitstream_buffer = 0;
2478 upload_tile_group_obu(
2479 pD3D12Enc,
2480 tile_group_obu_size,
2481 decode_tile_elements_size,
2482 associatedMetadata.m_StagingBitstreamConstruction,
2483 staging_bitstream_buffer_offset,
2484 src_driver_bitstream,
2485 associatedMetadata.comp_bit_destination,
2486 comp_bitstream_offset,
2487 pFrameSubregionMetadata,
2488 associatedMetadata.m_associatedEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_AV1TileCaps
2489 .TileSizeBytesMinus1 +
2490 1,
2491 associatedMetadata.m_associatedEncodeConfig.m_encoderSliceConfigDesc.m_TilesConfig_AV1.TilesPartition,
2492 currentTg,
2493 written_bytes_to_staging_bitstream_buffer,
2494 associatedMetadata.pWrittenCodecUnitsSizes);
2495
2496 staging_bitstream_buffer_offset += written_bytes_to_staging_bitstream_buffer;
2497 comp_bitstream_offset += tile_group_obu_size;
2498 writtenTileBytes += tile_group_obu_size;
2499
2500 // Flush batch with upload work and wait on this CPU thread for GPU work completion
2501 // for this case we have to do it within the loop, so the CUP arrays that are reused
2502 // on each loop are completely done being read by the GPU before we modify them.
2503 {
2504 struct pipe_fence_handle *pUploadGPUCompletionFence = NULL;
2505 pD3D12Enc->base.context->flush(pD3D12Enc->base.context,
2506 &pUploadGPUCompletionFence,
2507 PIPE_FLUSH_ASYNC | PIPE_FLUSH_HINT_FINISH);
2508 assert(pUploadGPUCompletionFence);
2509 debug_printf(
2510 "[d3d12_video_encoder] d3d12_video_encoder_build_post_encode_codec_bitstream_av1 - Waiting on GPU "
2511 "completion fence for "
2512 " uploading finalized codec headers to compressed bitstream.\n");
2513
2514 pD3D12Enc->m_pD3D12Screen->base.fence_finish(&pD3D12Enc->m_pD3D12Screen->base,
2515 NULL,
2516 pUploadGPUCompletionFence,
2517 OS_TIMEOUT_INFINITE);
2518 pD3D12Enc->m_pD3D12Screen->base.fence_reference(&pD3D12Enc->m_pD3D12Screen->base,
2519 &pUploadGPUCompletionFence,
2520 NULL);
2521 }
2522 }
2523 }
2524
2525 size_t extra_show_existing_frame_payload_bytes = 0;
2526 if (!picHdr.show_frame) {
2527
2528 // When writing in the bitstream a frame that will be accessed as reference by a frame we did not
2529 // write to the bitstream yet, let's store them for future show_existing_frame mechanism
2530 pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificStateDescAV1.pendingShowableFrames.push_back(
2531 associatedMetadata.m_associatedEncodeConfig.m_encoderPicParamsDesc.m_AV1PicData.PictureIndex);
2532
2533 } else { // picHdr.show_frame true
2534
2535 // Check if any of the pending "to be showed later" frames is present in the current frame references
2536 // and if so issue the show_existing_frame header and remove it from the pending list
2537
2538 for (auto pendingFrameIt =
2539 pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificStateDescAV1.pendingShowableFrames.begin();
2540 pendingFrameIt !=
2541 pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificStateDescAV1.pendingShowableFrames.end();) {
2542
2543 // Check if current frame references uses this pendingFrameIt
2544 int cur_ref_idx_matching_pending = -1;
2545 for (unsigned i = 0; i < ARRAY_SIZE(picHdr.ref_frame_idx) /*NUM_REF_FRAMES*/; i++) {
2546 if (
2547 // Is a valid reference
2548 (associatedMetadata.m_associatedEncodeConfig.m_encoderPicParamsDesc.m_AV1PicData
2549 .ReferenceFramesReconPictureDescriptors[picHdr.ref_frame_idx[i]]
2550 .ReconstructedPictureResourceIndex != UNUSED_VIRTUAL_DPB_SLOT_PHYSICAL_INDEX) &&
2551 // And matches the pending frame PictureIndex
2552 (associatedMetadata.m_associatedEncodeConfig.m_encoderPicParamsDesc.m_AV1PicData
2553 .ReferenceFramesReconPictureDescriptors[picHdr.ref_frame_idx[i]]
2554 .PictureIndex == *pendingFrameIt /*PictureIndex*/)) {
2555
2556 // Store the reference index
2557 cur_ref_idx_matching_pending = picHdr.ref_frame_idx[i];
2558 break;
2559 }
2560 }
2561
2562 // If we found a reference of the current frame using pendingFrameIt,
2563 // - Issue the show_existing_frame header
2564 // - Remove it from the pending list
2565 if (cur_ref_idx_matching_pending >= 0) {
2566 size_t staging_buf_offset = pD3D12Enc->m_BitstreamHeadersBuffer.size();
2567
2568
2569 size_t writtenTemporalDelimBytes = 0;
2570 if (D3D12_VIDEO_AV1_INSERT_SHOW_EXISTING_FRAME_HEADER) {
2571 pAV1BitstreamBuilder->write_temporal_delimiter_obu(
2572 pD3D12Enc->m_BitstreamHeadersBuffer,
2573 pD3D12Enc->m_BitstreamHeadersBuffer.begin() + staging_buf_offset, // placingPositionStart
2574 writtenTemporalDelimBytes // Bytes Written AFTER placingPositionStart arg above
2575 );
2576 }
2577 associatedMetadata.pWrittenCodecUnitsSizes.push_back(writtenTemporalDelimBytes);
2578 assert(writtenTemporalDelimBytes == (pD3D12Enc->m_BitstreamHeadersBuffer.size() - staging_buf_offset));
2579
2580 // Add current pending frame being processed in the loop
2581 extra_show_existing_frame_payload_bytes += writtenTemporalDelimBytes;
2582
2583 debug_printf("Written OBU_TEMPORAL_DELIMITER bytes: %" PRIu64 "\n", static_cast<uint64_t>(writtenTemporalDelimBytes));
2584
2585 size_t writtenShowExistingFrameBytes = 0;
2586 av1_pic_header_t showExistingPicHdr = {};
2587 showExistingPicHdr.show_existing_frame = 1;
2588 showExistingPicHdr.frame_to_show_map_idx = cur_ref_idx_matching_pending;
2589
2590 if (D3D12_VIDEO_AV1_INSERT_SHOW_EXISTING_FRAME_HEADER) {
2591 pAV1BitstreamBuilder->write_frame_header(
2592 NULL, // No seq header necessary for show_existing_frame
2593 &showExistingPicHdr,
2594 OBU_FRAME_HEADER,
2595 0, // No tile info for OBU_FRAME_HEADER
2596 pD3D12Enc->m_BitstreamHeadersBuffer,
2597 pD3D12Enc->m_BitstreamHeadersBuffer.begin() + staging_buf_offset +
2598 writtenTemporalDelimBytes, // placingPositionStart
2599 writtenShowExistingFrameBytes // Bytes Written AFTER placingPositionStart arg above
2600 );
2601 }
2602 associatedMetadata.pWrittenCodecUnitsSizes.push_back(writtenShowExistingFrameBytes);
2603
2604 assert(writtenShowExistingFrameBytes ==
2605 (pD3D12Enc->m_BitstreamHeadersBuffer.size() - staging_buf_offset - writtenTemporalDelimBytes));
2606
2607 // Add current pending frame being processed in the loop
2608 extra_show_existing_frame_payload_bytes += writtenShowExistingFrameBytes;
2609
2610 assert(pD3D12Enc->m_BitstreamHeadersBuffer.size() ==
2611 (staging_buf_offset + writtenShowExistingFrameBytes + writtenTemporalDelimBytes));
2612
2613 // Upload headers to the finalized compressed bitstream buffer
2614 // Note: The buffer_subdata is queued in pD3D12Enc->base.context but doesn't execute immediately
2615 pD3D12Enc->base.context->buffer_subdata(pD3D12Enc->base.context, // context
2616 associatedMetadata.comp_bit_destination, // comp. bitstream
2617 PIPE_MAP_WRITE, // usage PIPE_MAP_x
2618 comp_bitstream_offset, // offset
2619 writtenShowExistingFrameBytes + writtenTemporalDelimBytes,
2620 pD3D12Enc->m_BitstreamHeadersBuffer.data() + staging_buf_offset);
2621
2622 comp_bitstream_offset += writtenShowExistingFrameBytes;
2623 comp_bitstream_offset += writtenTemporalDelimBytes;
2624
2625 debug_printf("Written show_existing_frame OBU_FRAME header for previous frame with PictureIndex %d (Used "
2626 "in current frame ref_frame_idx[%" PRIu32 "]) bytes: %" PRIu64 "\n",
2627 *pendingFrameIt /*PictureIndex*/,
2628 showExistingPicHdr.frame_to_show_map_idx,
2629 static_cast<uint64_t>(writtenShowExistingFrameBytes));
2630
2631 // Remove it from the list of pending frames
2632 pendingFrameIt =
2633 pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificStateDescAV1.pendingShowableFrames.erase(
2634 pendingFrameIt);
2635 } else {
2636 pendingFrameIt++;
2637 }
2638 }
2639
2640 // Flush again if uploaded show_existing_frame header(s) to bitstream.
2641 if (extra_show_existing_frame_payload_bytes) {
2642 struct pipe_fence_handle *pUploadGPUCompletionFence = NULL;
2643 pD3D12Enc->base.context->flush(pD3D12Enc->base.context,
2644 &pUploadGPUCompletionFence,
2645 PIPE_FLUSH_ASYNC | PIPE_FLUSH_HINT_FINISH);
2646 assert(pUploadGPUCompletionFence);
2647 debug_printf("[d3d12_video_encoder] [show_existing_frame extra headers upload] "
2648 "d3d12_video_encoder_build_post_encode_codec_bitstream_av1 - Waiting on GPU "
2649 "completion fence for "
2650 " uploading finalized codec headers to compressed bitstream.\n");
2651
2652 pD3D12Enc->m_pD3D12Screen->base.fence_finish(&pD3D12Enc->m_pD3D12Screen->base,
2653 NULL,
2654 pUploadGPUCompletionFence,
2655 OS_TIMEOUT_INFINITE);
2656 pD3D12Enc->m_pD3D12Screen->base.fence_reference(&pD3D12Enc->m_pD3D12Screen->base,
2657 &pUploadGPUCompletionFence,
2658 NULL);
2659 }
2660 }
2661
2662 // d3d12_resource_from_resource calls AddRef to it so this should only be deleting
2663 // the pipe_resource wrapping object and not the underlying spStagingBitstream
2664 pipe_resource_reference(&src_driver_bitstream, NULL);
2665 assert(associatedMetadata.spStagingBitstream.Get());
2666
2667 // Unmap the metadata buffer tmp storage
2668 pipe_buffer_unmap(pD3D12Enc->base.context, mapTransferMetadata);
2669 pipe_resource_reference(&pPipeResolvedMetadataBuffer, NULL);
2670
2671 assert((writtenSequenceBytes + writtenTemporalDelimBytes + writtenFrameBytes +
2672 extra_show_existing_frame_payload_bytes) == pD3D12Enc->m_BitstreamHeadersBuffer.size());
2673
2674 uint32_t total_bytes_written = static_cast<uint32_t>(writtenSequenceBytes + writtenTemporalDelimBytes + writtenFrameBytes +
2675 writtenTileBytes + extra_show_existing_frame_payload_bytes);
2676 assert(std::accumulate(associatedMetadata.pWrittenCodecUnitsSizes.begin(), associatedMetadata.pWrittenCodecUnitsSizes.end(), 0u) ==
2677 static_cast<uint64_t>(total_bytes_written));
2678 return total_bytes_written;
2679 }
2680
2681 void
upload_tile_group_obu(struct d3d12_video_encoder * pD3D12Enc,size_t tile_group_obu_size,size_t decode_tile_elements_size,std::vector<uint8_t> & staging_bitstream_buffer,size_t staging_bitstream_buffer_offset,pipe_resource * src_driver_bitstream,pipe_resource * comp_bit_destination,size_t comp_bit_destination_offset,const D3D12_VIDEO_ENCODER_FRAME_SUBREGION_METADATA * pFrameSubregionMetadata,size_t TileSizeBytes,const D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_TILES & TilesPartition,const av1_tile_group_t & tileGroup,size_t & written_bytes_to_staging_bitstream_buffer,std::vector<uint64_t> & pWrittenCodecUnitsSizes)2682 upload_tile_group_obu(struct d3d12_video_encoder *pD3D12Enc,
2683 size_t tile_group_obu_size,
2684 size_t decode_tile_elements_size,
2685 std::vector<uint8_t> &staging_bitstream_buffer,
2686 size_t staging_bitstream_buffer_offset,
2687 pipe_resource *src_driver_bitstream,
2688 pipe_resource *comp_bit_destination,
2689 size_t comp_bit_destination_offset,
2690 const D3D12_VIDEO_ENCODER_FRAME_SUBREGION_METADATA *pFrameSubregionMetadata,
2691 size_t TileSizeBytes, // Pass already +1'd from TileSizeBytesMinus1
2692 const D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_TILES &TilesPartition,
2693 const av1_tile_group_t &tileGroup,
2694 size_t &written_bytes_to_staging_bitstream_buffer,
2695 std::vector<uint64_t> &pWrittenCodecUnitsSizes)
2696 {
2697 debug_printf("[Tile group start %d to end %d] Writing to comp_bit_destination %p starts at offset %" PRIu64 "\n",
2698 tileGroup.tg_start,
2699 tileGroup.tg_end,
2700 comp_bit_destination,
2701 static_cast<uint64_t>(comp_bit_destination_offset));
2702
2703 debug_printf("[Tile group start %d to end %d] Using staging_bitstream_buffer %p at offset %" PRIu64
2704 " to write the tile_obu_group() prefix syntax: tile_start_and_end_present_flag, tg_start, tg_end and "
2705 "the tile_size_minus1\n",
2706 tileGroup.tg_start,
2707 tileGroup.tg_end,
2708 staging_bitstream_buffer.data(),
2709 static_cast<uint64_t>(staging_bitstream_buffer_offset));
2710
2711 // Reserve space upfront in the scratch storage
2712 // Do not modify anything before staging_bitstream_buffer_offset
2713
2714 size_t tile_obu_prefix_size = tile_group_obu_size - decode_tile_elements_size;
2715 if (staging_bitstream_buffer.size() < (staging_bitstream_buffer_offset + tile_obu_prefix_size))
2716 staging_bitstream_buffer.resize(staging_bitstream_buffer_offset + tile_obu_prefix_size);
2717
2718 d3d12_video_encoder_bitstream bitstream_tile_group_obu;
2719 bitstream_tile_group_obu.setup_bitstream(staging_bitstream_buffer.size(),
2720 staging_bitstream_buffer.data(),
2721 staging_bitstream_buffer_offset);
2722
2723 uint8_t NumTiles = TilesPartition.ColCount * TilesPartition.RowCount;
2724 bool tile_start_and_end_present_flag = !(tileGroup.tg_start == 0 && (tileGroup.tg_end == (NumTiles - 1)));
2725 if (NumTiles > 1)
2726 bitstream_tile_group_obu.put_bits(1,
2727 tile_start_and_end_present_flag); // tile_start_and_end_present_flag f(1)
2728
2729 if (!(NumTiles == 1 || !tile_start_and_end_present_flag)) {
2730 uint8_t tileBits = log2(TilesPartition.ColCount) + log2(TilesPartition.RowCount);
2731 bitstream_tile_group_obu.put_bits(tileBits, tileGroup.tg_start); // tg_start f(tileBits)
2732 bitstream_tile_group_obu.put_bits(tileBits, tileGroup.tg_end); // tg_end f(tileBits)
2733 }
2734
2735 bitstream_tile_group_obu.put_aligning_bits(); // byte_alignment()
2736
2737 bitstream_tile_group_obu.flush();
2738
2739 size_t bitstream_tile_group_obu_bytes = bitstream_tile_group_obu.get_byte_count() - staging_bitstream_buffer_offset;
2740
2741 debug_printf("[Tile group start %d to end %d] Written %" PRIu64
2742 " bitstream_tile_group_obu_bytes at staging_bitstream_buffer %p at offset %" PRIu64
2743 " for tile_obu_group() prefix syntax: tile_start_and_end_present_flag, tg_start, tg_end\n",
2744 tileGroup.tg_start,
2745 tileGroup.tg_end,
2746 static_cast<uint64_t>(bitstream_tile_group_obu_bytes),
2747 staging_bitstream_buffer.data(),
2748 static_cast<uint64_t>(staging_bitstream_buffer_offset));
2749
2750
2751 // Save this to compare the final written destination byte size against the expected tile_group_obu_size
2752 // at the end of the function
2753 ASSERTED size_t comp_bit_destination_offset_before_upload = comp_bit_destination_offset;
2754
2755 // Upload first part of the header to compressed bitstream destination
2756 // Note: The buffer_subdata is queued in pD3D12Enc->base.context but doesn't execute immediately
2757 if (bitstream_tile_group_obu_bytes > 0) {
2758 pD3D12Enc->base.context->buffer_subdata(
2759 pD3D12Enc->base.context, // context
2760 comp_bit_destination, // comp. bitstream
2761 PIPE_MAP_WRITE, // usage PIPE_MAP_x
2762 comp_bit_destination_offset, // offset
2763 bitstream_tile_group_obu_bytes, // size
2764 staging_bitstream_buffer.data() + staging_bitstream_buffer_offset); // data
2765
2766 debug_printf("[Tile group start %d to end %d] Uploading %" PRIu64 " bytes"
2767 " for tile_obu_group() prefix syntax: tile_start_and_end_present_flag, tg_start, tg_end"
2768 " from staging_bitstream_buffer %p at offset %" PRIu64
2769 " to comp_bit_destination %p at offset %" PRIu64 "\n",
2770 tileGroup.tg_start,
2771 tileGroup.tg_end,
2772 static_cast<uint64_t>(bitstream_tile_group_obu_bytes),
2773 staging_bitstream_buffer.data(),
2774 static_cast<uint64_t>(staging_bitstream_buffer_offset),
2775 comp_bit_destination,
2776 static_cast<uint64_t>(comp_bit_destination_offset));
2777
2778 comp_bit_destination_offset += bitstream_tile_group_obu_bytes;
2779 written_bytes_to_staging_bitstream_buffer += bitstream_tile_group_obu_bytes;
2780 }
2781
2782 size_t src_offset = 0;
2783 for (UINT64 TileIdx = tileGroup.tg_start; TileIdx <= tileGroup.tg_end; TileIdx++) {
2784 size_t tile_size = pFrameSubregionMetadata[TileIdx].bSize - pFrameSubregionMetadata[TileIdx].bStartOffset;
2785 // The i-th tile is read from the src_buffer[offset] with offset = [sum j = (0, (i-1)){ tile[j].bSize }] +
2786 // tile[i].bStartOffset
2787 size_t src_buf_tile_position = src_offset + pFrameSubregionMetadata[TileIdx].bStartOffset;
2788 src_offset += pFrameSubregionMetadata[TileIdx].bSize;
2789
2790 // tile_size_minus_1 not coded for last tile
2791 if ((TileIdx != tileGroup.tg_end)) {
2792 bitstream_tile_group_obu.put_le_bytes(TileSizeBytes, // tile_size_minus_1 le(TileSizeBytes)
2793 tile_size - 1 /* convert to ..._minus_1 */);
2794 bitstream_tile_group_obu.flush();
2795
2796 debug_printf("[Tile group start %d to end %d] [TileIdx %" PRIu64 "] Written %" PRIu64
2797 " written_bytes_to_staging_bitstream_buffer at staging_bitstream_buffer %p at offset %" PRIu64
2798 " for the tile_size_minus1 syntax\n",
2799 tileGroup.tg_start,
2800 tileGroup.tg_end,
2801 TileIdx,
2802 static_cast<uint64_t>(TileSizeBytes),
2803 staging_bitstream_buffer.data(),
2804 static_cast<uint64_t>(written_bytes_to_staging_bitstream_buffer + staging_bitstream_buffer_offset));
2805
2806 // Upload current tile_size_minus_1
2807 // Note: The buffer_subdata is queued in pD3D12Enc->base.context but doesn't execute immediately
2808 pD3D12Enc->base.context->buffer_subdata(pD3D12Enc->base.context, // context
2809 comp_bit_destination, // comp. bitstream
2810 PIPE_MAP_WRITE, // usage PIPE_MAP_x
2811 comp_bit_destination_offset, // offset
2812 TileSizeBytes, // size
2813 staging_bitstream_buffer.data() +
2814 written_bytes_to_staging_bitstream_buffer +
2815 staging_bitstream_buffer_offset); // data
2816
2817 debug_printf("[Tile group start %d to end %d] [TileIdx %" PRIu64 "] Uploading %" PRIu64 " bytes"
2818 " for tile_obu_group() prefix syntax: tile_size_minus_1"
2819 " from staging_bitstream_buffer %p at offset %" PRIu64
2820 " to comp_bit_destination %p at offset %" PRIu64 "\n",
2821 tileGroup.tg_start,
2822 tileGroup.tg_end,
2823 TileIdx,
2824 static_cast<uint64_t>(TileSizeBytes),
2825 staging_bitstream_buffer.data(),
2826 static_cast<uint64_t>(written_bytes_to_staging_bitstream_buffer + staging_bitstream_buffer_offset),
2827 comp_bit_destination,
2828 static_cast<uint64_t>(comp_bit_destination_offset));
2829
2830 comp_bit_destination_offset += TileSizeBytes;
2831 written_bytes_to_staging_bitstream_buffer += TileSizeBytes;
2832 }
2833
2834 // Now copy the decode_tile() element from the driver staging GPU buffer onto the finalized GPU buffer
2835
2836 struct pipe_box src_box = {
2837 static_cast<int>(src_buf_tile_position), // x
2838 0, // y
2839 0, // z
2840 static_cast<int>(tile_size), // width
2841 1, // height
2842 1 // depth
2843 };
2844
2845 pD3D12Enc->base.context->resource_copy_region(pD3D12Enc->base.context, // ctx
2846 comp_bit_destination, // dst
2847 0, // dst_level
2848 comp_bit_destination_offset, // dstX
2849 0, // dstY
2850 0, // dstZ
2851 src_driver_bitstream, // src
2852 0, // src level
2853 &src_box);
2854
2855 debug_printf("[Tile group start %d to end %d] [TileIdx %" PRIu64 "] Written %" PRIu64
2856 " tile_size bytes data from src_driver_bitstream %p at offset %" PRIu64
2857 " into comp_bit_destination %p at offset %" PRIu64 "\n",
2858 tileGroup.tg_start,
2859 tileGroup.tg_end,
2860 TileIdx,
2861 static_cast<uint64_t>(tile_size),
2862 src_driver_bitstream,
2863 static_cast<uint64_t>(src_buf_tile_position),
2864 comp_bit_destination,
2865 static_cast<uint64_t>(comp_bit_destination_offset));
2866
2867 comp_bit_destination_offset += tile_size;
2868
2869 size_t cur_tile_reportable_size = tile_size;
2870 if (TileIdx != tileGroup.tg_end)
2871 cur_tile_reportable_size += TileSizeBytes; /* extra tile_size_bytes_minus1 in all tiles except last*/
2872 if (TileIdx == 0)
2873 cur_tile_reportable_size += bitstream_tile_group_obu_bytes; // part of the obu tile group header (make part of first tile)
2874 pWrittenCodecUnitsSizes.push_back(cur_tile_reportable_size);
2875 }
2876
2877 // Make sure we wrote the expected bytes that match the obu_size elements
2878 // in the OBUs wrapping this uploaded tile_group_obu
2879 assert((comp_bit_destination_offset - comp_bit_destination_offset_before_upload) == tile_group_obu_size);
2880 }
2881
2882 void
d3d12_video_encoder_store_current_picture_references_av1(d3d12_video_encoder * pD3D12Enc,uint64_t current_metadata_slot)2883 d3d12_video_encoder_store_current_picture_references_av1(d3d12_video_encoder *pD3D12Enc, uint64_t current_metadata_slot)
2884 {
2885 // Update DX12 picparams for post execution (get_feedback) after d3d12_video_encoder_references_manager_av1
2886 // changes
2887 pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].m_associatedEncodeConfig.m_encoderPicParamsDesc =
2888 pD3D12Enc->m_currentEncodeConfig.m_encoderPicParamsDesc;
2889 }
2890