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