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