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