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_encoder_references_manager_h264.h"
25 #include <algorithm>
26 #include <string>
27 #include "d3d12_screen.h"
28 #include "d3d12_video_buffer.h"
29 #include "d3d12_resource.h"
30
31 using namespace std;
32
33 bool
get_current_frame_picture_control_data(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA & codecAllocation)34 d3d12_video_encoder_references_manager_h264::get_current_frame_picture_control_data(
35 D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA &codecAllocation)
36 {
37 assert(codecAllocation.DataSize == sizeof(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_H264));
38 if (codecAllocation.DataSize != sizeof(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_H264))
39 return false;
40
41 *codecAllocation.pH264PicData = m_curFrameState;
42
43 return true;
44 }
45
46 D3D12_VIDEO_ENCODE_REFERENCE_FRAMES
get_current_reference_frames()47 d3d12_video_encoder_references_manager_h264::get_current_reference_frames()
48 {
49 D3D12_VIDEO_ENCODE_REFERENCE_FRAMES retVal = { 0,
50 // ppTexture2Ds
51 nullptr,
52 // pSubresources
53 nullptr };
54
55 // Return nullptr for fully intra frames (eg IDR)
56 // and return references information for inter frames (eg.P/B) and I frame that doesn't flush DPB
57
58 if ((m_curFrameState.FrameType != D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_IDR_FRAME) &&
59 (m_curFrameState.FrameType != D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_I_FRAME)) {
60 retVal.NumTexture2Ds = static_cast<UINT>(m_CurrentFrameReferencesData.ReferenceTextures.pResources.size());
61 retVal.ppTexture2Ds = m_CurrentFrameReferencesData.ReferenceTextures.pResources.data();
62
63 // D3D12 Encode expects null subresources for AoT
64 bool isAoT = (std::all_of(m_CurrentFrameReferencesData.ReferenceTextures.pSubresources.begin(),
65 m_CurrentFrameReferencesData.ReferenceTextures.pSubresources.end(),
66 [](UINT i) { return i == 0; }));
67 retVal.pSubresources = isAoT ? nullptr : m_CurrentFrameReferencesData.ReferenceTextures.pSubresources.data();
68 }
69
70 return retVal;
71 }
72
73 static const char *
d3d12_video_encoder_friendly_frame_type_h264(D3D12_VIDEO_ENCODER_FRAME_TYPE_H264 picType)74 d3d12_video_encoder_friendly_frame_type_h264(D3D12_VIDEO_ENCODER_FRAME_TYPE_H264 picType)
75 {
76 switch (picType) {
77 case D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_P_FRAME:
78 {
79 return "H264_P_FRAME";
80 } break;
81 case D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_B_FRAME:
82 {
83 return "H264_B_FRAME";
84 } break;
85 case D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_I_FRAME:
86 {
87 return "H264_I_FRAME";
88 } break;
89 case D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_IDR_FRAME:
90 {
91 return "H264_IDR_FRAME";
92 } break;
93 default:
94 {
95 unreachable("Unsupported pipe_h2645_enc_picture_type");
96 } break;
97 }
98 }
99
100 void
print_l0_l1_lists()101 d3d12_video_encoder_references_manager_h264::print_l0_l1_lists()
102 {
103 debug_printf(
104 "[D3D12 Video Encoder Picture Manager H264] L0 (%d entries) and L1 (%d entries) lists for frame with POC "
105 "%d (frame_num: %d) and frame_type %s are:\n",
106 m_curFrameState.List0ReferenceFramesCount,
107 m_curFrameState.List1ReferenceFramesCount,
108 m_curFrameState.PictureOrderCountNumber,
109 m_curFrameState.FrameDecodingOrderNumber,
110 d3d12_video_encoder_friendly_frame_type_h264(m_curFrameState.FrameType));
111
112 if ((D3D12_DEBUG_VERBOSE & d3d12_debug) &&
113 ((m_curFrameState.FrameType == D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_P_FRAME) ||
114 (m_curFrameState.FrameType == D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_B_FRAME))) {
115 std::string list0ContentsString;
116 for (uint32_t idx = 0; idx < m_curFrameState.List0ReferenceFramesCount; idx++) {
117 uint32_t value = m_curFrameState.pList0ReferenceFrames[idx];
118 list0ContentsString += "{ DPBidx: ";
119 list0ContentsString += std::to_string(value);
120 list0ContentsString += " - POC: ";
121 list0ContentsString += std::to_string(
122 m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors[value].PictureOrderCountNumber);
123 list0ContentsString += " - FrameDecodingOrderNumber: ";
124 list0ContentsString += std::to_string(
125 m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors[value].FrameDecodingOrderNumber);
126 list0ContentsString += "}\n";
127 }
128
129 debug_printf("[D3D12 Video Encoder Picture Manager H264] L0 list (%d entries) for frame with POC %d - frame_num "
130 "(%d) is: \n %s \n",
131 m_curFrameState.List0ReferenceFramesCount,
132 m_curFrameState.PictureOrderCountNumber,
133 m_curFrameState.FrameDecodingOrderNumber,
134 list0ContentsString.c_str());
135
136 std::string modificationOrderList0ContentsString;
137 for (uint32_t idx = 0; idx < m_curFrameState.List0RefPicModificationsCount; idx++) {
138 D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_H264_REFERENCE_PICTURE_LIST_MODIFICATION_OPERATION value =
139 m_curFrameState.pList0RefPicModifications[idx];
140 modificationOrderList0ContentsString += "{ modification_of_pic_nums_idc: ";
141 modificationOrderList0ContentsString += std::to_string(value.modification_of_pic_nums_idc);
142 modificationOrderList0ContentsString += " - abs_diff_pic_num_minus1: ";
143 modificationOrderList0ContentsString += std::to_string(value.abs_diff_pic_num_minus1);
144 modificationOrderList0ContentsString += " - long_term_pic_num: ";
145 modificationOrderList0ContentsString += std::to_string(value.long_term_pic_num);
146 modificationOrderList0ContentsString += "}\n";
147 }
148 debug_printf("[D3D12 Video Encoder Picture Manager H264] L0 modification list (%d entries) for frame with POC %d "
149 "- frame_num "
150 "(%d) temporal_id (%d) is: \n %s \n",
151 m_curFrameState.List0RefPicModificationsCount,
152 m_curFrameState.PictureOrderCountNumber,
153 m_curFrameState.FrameDecodingOrderNumber,
154 m_curFrameState.TemporalLayerIndex,
155 modificationOrderList0ContentsString.c_str());
156
157 std::string list1ContentsString;
158 for (uint32_t idx = 0; idx < m_curFrameState.List1ReferenceFramesCount; idx++) {
159 uint32_t value = m_curFrameState.pList1ReferenceFrames[idx];
160 list1ContentsString += "{ DPBidx: ";
161 list1ContentsString += std::to_string(value);
162 list1ContentsString += " - POC: ";
163 list1ContentsString += std::to_string(
164 m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors[value].PictureOrderCountNumber);
165 list1ContentsString += " - FrameDecodingOrderNumber: ";
166 list1ContentsString += std::to_string(
167 m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors[value].FrameDecodingOrderNumber);
168 list1ContentsString += "}\n";
169 }
170
171 debug_printf("[D3D12 Video Encoder Picture Manager H264] L1 list (%d entries) for frame with POC %d - frame_num "
172 "(%d) is: \n %s \n",
173 m_curFrameState.List1ReferenceFramesCount,
174 m_curFrameState.PictureOrderCountNumber,
175 m_curFrameState.FrameDecodingOrderNumber,
176 list1ContentsString.c_str());
177
178 std::string modificationOrderList1ContentsString;
179 for (uint32_t idx = 0; idx < m_curFrameState.List1RefPicModificationsCount; idx++) {
180 D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_H264_REFERENCE_PICTURE_LIST_MODIFICATION_OPERATION value =
181 m_curFrameState.pList1RefPicModifications[idx];
182 modificationOrderList1ContentsString += "{ modification_of_pic_nums_idc: ";
183 modificationOrderList1ContentsString += std::to_string(value.modification_of_pic_nums_idc);
184 modificationOrderList1ContentsString += " - abs_diff_pic_num_minus1: ";
185 modificationOrderList1ContentsString += std::to_string(value.abs_diff_pic_num_minus1);
186 modificationOrderList1ContentsString += " - long_term_pic_num: ";
187 modificationOrderList1ContentsString += std::to_string(value.long_term_pic_num);
188 modificationOrderList1ContentsString += "}\n";
189 }
190
191 debug_printf("[D3D12 Video Encoder Picture Manager H264] L1 modification list (%d entries) for frame with POC %d "
192 "- frame_num "
193 "(%d) temporal_id (%d) is: \n %s \n",
194 m_curFrameState.List1RefPicModificationsCount,
195 m_curFrameState.PictureOrderCountNumber,
196 m_curFrameState.FrameDecodingOrderNumber,
197 m_curFrameState.TemporalLayerIndex,
198 modificationOrderList1ContentsString.c_str());
199 }
200 }
201
202 void
print_dpb()203 d3d12_video_encoder_references_manager_h264::print_dpb()
204 {
205 if (D3D12_DEBUG_VERBOSE & d3d12_debug) {
206 std::string dpbContents;
207 for (uint32_t dpbResIdx = 0;
208 dpbResIdx < m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.size();
209 dpbResIdx++) {
210 auto &dpbDesc = m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors[dpbResIdx];
211
212 dpbContents += "{ DPBidx: ";
213 dpbContents += std::to_string(dpbResIdx);
214
215 if (dpbDesc.PictureOrderCountNumber == m_curFrameState.PictureOrderCountNumber) {
216 dpbContents += " - CURRENT FRAME RECON PIC ";
217 }
218
219 dpbContents += " - POC: ";
220 dpbContents += std::to_string(dpbDesc.PictureOrderCountNumber);
221 dpbContents += " - FrameDecodingOrderNumber: ";
222 dpbContents += std::to_string(dpbDesc.FrameDecodingOrderNumber);
223 dpbContents += " - DPBStorageIdx: ";
224 dpbContents += std::to_string(dpbDesc.ReconstructedPictureResourceIndex);
225 dpbContents += " - DPBStorageResourcePtr: ";
226 char strBuf[256];
227 memset(&strBuf, '\0', 256);
228 sprintf(strBuf,
229 "%p",
230 m_CurrentFrameReferencesData.ReferenceTextures.pResources[dpbDesc.ReconstructedPictureResourceIndex]);
231 dpbContents += std::string(strBuf);
232 dpbContents += " - DPBStorageSubresource: ";
233 dpbContents += std::to_string(
234 m_CurrentFrameReferencesData.ReferenceTextures.pSubresources[dpbDesc.ReconstructedPictureResourceIndex]);
235 dpbContents += "}\n";
236 }
237
238 debug_printf("[D3D12 Video Encoder Picture Manager H264] DPB has %d frames - DPB references for frame with POC "
239 "%d (frame_num: %d) are: \n %s \n",
240 static_cast<UINT>(m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.size()),
241 m_curFrameState.PictureOrderCountNumber,
242 m_curFrameState.FrameDecodingOrderNumber,
243 dpbContents.c_str());
244 }
245 }
246
247 static D3D12_VIDEO_ENCODER_FRAME_TYPE_H264
d3d12_video_encoder_convert_frame_type_h264(enum pipe_h2645_enc_picture_type picType)248 d3d12_video_encoder_convert_frame_type_h264(enum pipe_h2645_enc_picture_type picType)
249 {
250 switch (picType) {
251 case PIPE_H2645_ENC_PICTURE_TYPE_P:
252 {
253 return D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_P_FRAME;
254 } break;
255 case PIPE_H2645_ENC_PICTURE_TYPE_B:
256 {
257 return D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_B_FRAME;
258 } break;
259 case PIPE_H2645_ENC_PICTURE_TYPE_I:
260 {
261 return D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_I_FRAME;
262 } break;
263 case PIPE_H2645_ENC_PICTURE_TYPE_IDR:
264 {
265 return D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_IDR_FRAME;
266 } break;
267 default:
268 {
269 unreachable("Unsupported pipe_h2645_enc_picture_type");
270 } break;
271 }
272 }
273
274 void
begin_frame(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA curFrameData,bool bUsedAsReference,struct pipe_picture_desc * picture)275 d3d12_video_encoder_references_manager_h264::begin_frame(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA curFrameData,
276 bool bUsedAsReference,
277 struct pipe_picture_desc *picture)
278 {
279 m_curFrameState = *curFrameData.pH264PicData;
280 m_isCurrentFrameUsedAsReference = bUsedAsReference;
281
282 struct pipe_h264_enc_picture_desc *h264Pic = (struct pipe_h264_enc_picture_desc *) picture;
283
284 ///
285 /// Copy DPB snapshot from pipe params
286 ///
287
288 m_curFrameState.ReferenceFramesReconPictureDescriptorsCount =
289 static_cast<uint32_t>(m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.size());
290 m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.resize(h264Pic->dpb_size);
291 m_CurrentFrameReferencesData.ReferenceTextures.pResources.resize(h264Pic->dpb_size);
292 m_CurrentFrameReferencesData.ReferenceTextures.pSubresources.resize(h264Pic->dpb_size);
293 m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.resize(h264Pic->dpb_size);
294 for (uint8_t i = 0; i < h264Pic->dpb_size; i++) {
295 //
296 // Set entry DPB members
297 //
298 m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors[i].FrameDecodingOrderNumber =
299 h264Pic->dpb[i].frame_idx;
300 m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors[i].IsLongTermReference =
301 h264Pic->dpb[i].is_ltr;
302 m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors[i].LongTermPictureIdx =
303 h264Pic->dpb[i].is_ltr ? h264Pic->dpb[i].frame_idx : 0u;
304 m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors[i].PictureOrderCountNumber =
305 h264Pic->dpb[i].pic_order_cnt;
306 // mirror indices between DPB entries and allocation arrays
307 m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors[i].ReconstructedPictureResourceIndex = i;
308 m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors[i].TemporalLayerIndex =
309 h264Pic->dpb[i].temporal_id;
310
311 //
312 // Set texture allocations
313 //
314
315 struct d3d12_video_buffer *vidbuf = (struct d3d12_video_buffer *) h264Pic->dpb[i].buffer;
316 m_CurrentFrameReferencesData.ReferenceTextures.pResources[i] = d3d12_resource_resource(vidbuf->texture);
317 m_CurrentFrameReferencesData.ReferenceTextures.pSubresources[i] = vidbuf->idx_texarray_slots;
318
319 if (h264Pic->dpb[i].pic_order_cnt == h264Pic->pic_order_cnt) {
320 m_CurrentFrameReferencesData.ReconstructedPicTexture.pReconstructedPicture =
321 m_CurrentFrameReferencesData.ReferenceTextures.pResources[i];
322 m_CurrentFrameReferencesData.ReconstructedPicTexture.ReconstructedPictureSubresource =
323 m_CurrentFrameReferencesData.ReferenceTextures.pSubresources[i];
324 }
325 }
326
327 ///
328 /// Set pic control info
329 ///
330
331 m_curFrameState.idr_pic_id = h264Pic->idr_pic_id;
332 m_curFrameState.FrameType = d3d12_video_encoder_convert_frame_type_h264(h264Pic->picture_type);
333 m_curFrameState.PictureOrderCountNumber = h264Pic->pic_order_cnt;
334 m_curFrameState.FrameDecodingOrderNumber = h264Pic->slice.frame_num;
335
336 ///
337 /// Set MMCO info
338 ///
339
340 // Deep Copy MMCO list
341 m_curFrameState.pRefPicMarkingOperationsCommands = nullptr;
342 m_curFrameState.RefPicMarkingOperationsCommandsCount = 0u;
343 m_curFrameState.adaptive_ref_pic_marking_mode_flag = 0u;
344
345 if (m_curFrameState.FrameType != D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_IDR_FRAME) {
346
347 // Only send mmco ops to IHV driver on non-idr frames since dec_ref_pic_marking() in the IDR slice headers doesn't
348 // have the memory operation list coded in the bitstream
349 m_curFrameState.adaptive_ref_pic_marking_mode_flag = h264Pic->slice.adaptive_ref_pic_marking_mode_flag;
350 if (m_curFrameState.adaptive_ref_pic_marking_mode_flag) {
351 m_curFrameState.RefPicMarkingOperationsCommandsCount = h264Pic->slice.num_ref_pic_marking_operations;
352 m_CurrentFrameReferencesData.pMemoryOps.resize(m_curFrameState.RefPicMarkingOperationsCommandsCount);
353 for (unsigned i = 0; i < m_curFrameState.RefPicMarkingOperationsCommandsCount; i++) {
354 m_CurrentFrameReferencesData.pMemoryOps[i].difference_of_pic_nums_minus1 =
355 h264Pic->slice.ref_pic_marking_operations[i].difference_of_pic_nums_minus1;
356 m_CurrentFrameReferencesData.pMemoryOps[i].long_term_frame_idx =
357 h264Pic->slice.ref_pic_marking_operations[i].long_term_frame_idx;
358 m_CurrentFrameReferencesData.pMemoryOps[i].long_term_pic_num =
359 h264Pic->slice.ref_pic_marking_operations[i].long_term_pic_num;
360 m_CurrentFrameReferencesData.pMemoryOps[i].max_long_term_frame_idx_plus1 =
361 h264Pic->slice.ref_pic_marking_operations[i].max_long_term_frame_idx_plus1;
362 m_CurrentFrameReferencesData.pMemoryOps[i].memory_management_control_operation =
363 h264Pic->slice.ref_pic_marking_operations[i].memory_management_control_operation;
364 }
365
366 // DX12 driver requires "End memory_management_control_operation syntax element loop" to be
367 // sent at the end of the list for coding the slice header when sending down mmco commands
368 if ((m_curFrameState.RefPicMarkingOperationsCommandsCount > 0) &&
369 m_CurrentFrameReferencesData.pMemoryOps[m_curFrameState.RefPicMarkingOperationsCommandsCount - 1]
370 .memory_management_control_operation != 0) {
371
372 // Add it if the frontend didn't send it
373 m_curFrameState.RefPicMarkingOperationsCommandsCount++;
374 D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_H264_REFERENCE_PICTURE_MARKING_OPERATION endMMCOOperation = {};
375 endMMCOOperation.memory_management_control_operation = 0u;
376 m_CurrentFrameReferencesData.pMemoryOps.push_back(endMMCOOperation);
377 }
378
379 m_curFrameState.pRefPicMarkingOperationsCommands = m_CurrentFrameReferencesData.pMemoryOps.data();
380 }
381 } else if (h264Pic->slice.long_term_reference_flag) {
382 assert(m_curFrameState.FrameType == D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_IDR_FRAME);
383 // See https://microsoft.github.io/DirectX-Specs/d3d/D3D12VideoEncoding.html
384 // Note that for marking an IDR frame as long term reference, the proposed explicit mechanism is to mark it as
385 // short term reference first, by setting D3D12_VIDEO_ENCODER_PICTURE_CONTROL_FLAG_USED_AS_REFERENCE_PICTURE when
386 // calling EncodeFrame for such IDR frame, and later promoting it to be a long term reference frame using memory
387 // management operation '3' Mark a short-term reference picture as "used for long-term reference" and assign a
388 // long-term frame index to it.
389 // Alternatively, if encoding an IDR frame and setting adaptive_ref_pic_marking_mode_flag = 1, the driver will
390 // assume that the client is attempting to set the H264 slice header long_term_reference_flag and will do so in
391 // the output bitstream for such EncodeFrame call.
392 m_curFrameState.adaptive_ref_pic_marking_mode_flag = 1;
393
394 // Workaround for D3D12 validation bug requiring pRefPicMarkingOperationsCommands for IDR frames
395 m_curFrameState.RefPicMarkingOperationsCommandsCount = 1u;
396 m_CurrentFrameReferencesData.pMemoryOps.resize(m_curFrameState.RefPicMarkingOperationsCommandsCount);
397 m_curFrameState.pRefPicMarkingOperationsCommands = m_CurrentFrameReferencesData.pMemoryOps.data();
398 }
399
400 ///
401 /// Set ref pic modifications info
402 ///
403 // d3d12 needs the array allocations passed in D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_H264
404 // to avoid copies, and taking advantage of the same memory layout with pipe, shallow copy them
405 // If these static asserts do not pass anymore, change below ALL OCCURRENCES OF reinterpret_casts between
406 // pipe_h264_ref_list_mod_entry and
407 // D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_H264_REFERENCE_PICTURE_LIST_MODIFICATION_OPERATION
408 static_assert(
409 sizeof(struct pipe_h264_ref_list_mod_entry) ==
410 sizeof(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_H264_REFERENCE_PICTURE_LIST_MODIFICATION_OPERATION));
411 static_assert(
412 offsetof(struct pipe_h264_ref_list_mod_entry, modification_of_pic_nums_idc) ==
413 offsetof(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_H264_REFERENCE_PICTURE_LIST_MODIFICATION_OPERATION,
414 modification_of_pic_nums_idc));
415 static_assert(
416 offsetof(struct pipe_h264_ref_list_mod_entry, abs_diff_pic_num_minus1) ==
417 offsetof(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_H264_REFERENCE_PICTURE_LIST_MODIFICATION_OPERATION,
418 abs_diff_pic_num_minus1));
419 static_assert(
420 offsetof(struct pipe_h264_ref_list_mod_entry, long_term_pic_num) ==
421 offsetof(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_H264_REFERENCE_PICTURE_LIST_MODIFICATION_OPERATION,
422 long_term_pic_num));
423
424 m_curFrameState.List0ReferenceFramesCount = 0;
425 m_curFrameState.pList0ReferenceFrames = nullptr;
426 m_curFrameState.List0RefPicModificationsCount = 0;
427 m_curFrameState.pList0RefPicModifications = nullptr;
428 m_curFrameState.List1ReferenceFramesCount = 0;
429 m_curFrameState.pList1ReferenceFrames = nullptr;
430 m_curFrameState.List1RefPicModificationsCount = 0;
431 m_curFrameState.pList1RefPicModifications = nullptr;
432 m_curFrameState.ReferenceFramesReconPictureDescriptorsCount = 0u;
433 m_curFrameState.pReferenceFramesReconPictureDescriptors = nullptr;
434
435 if ((m_curFrameState.FrameType == D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_P_FRAME) ||
436 (m_curFrameState.FrameType == D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_B_FRAME)) {
437
438 // Set DPB descriptors
439 m_curFrameState.ReferenceFramesReconPictureDescriptorsCount =
440 static_cast<UINT>(m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.size());
441 m_curFrameState.pReferenceFramesReconPictureDescriptors =
442 m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.data();
443
444 // Deep Copy L0 list
445 m_curFrameState.List0ReferenceFramesCount = h264Pic->num_ref_idx_l0_active_minus1 + 1;
446 m_CurrentFrameReferencesData.pList0ReferenceFrames.resize(m_curFrameState.List0ReferenceFramesCount);
447 for (unsigned i = 0; i < m_curFrameState.List0ReferenceFramesCount; i++)
448 m_CurrentFrameReferencesData.pList0ReferenceFrames[i] = h264Pic->ref_list0[i];
449 m_curFrameState.pList0ReferenceFrames = m_CurrentFrameReferencesData.pList0ReferenceFrames.data();
450
451 // Shallow Copy L0 ref modification list
452 m_curFrameState.List0RefPicModificationsCount = h264Pic->slice.num_ref_list0_mod_operations;
453 if (m_curFrameState.List0RefPicModificationsCount > 0) {
454 m_curFrameState.pList0RefPicModifications = reinterpret_cast<
455 D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_H264_REFERENCE_PICTURE_LIST_MODIFICATION_OPERATION *>(
456 &h264Pic->slice.ref_list0_mod_operations[0]);
457 // DX12 driver requires "End modification_of_pic_nums_idc syntax element loop" to be
458 // sent at the end of the list for coding the slice header when sending down reordering commands
459 assert((m_curFrameState.List0RefPicModificationsCount == 0) ||
460 m_curFrameState.pList0RefPicModifications[m_curFrameState.List0RefPicModificationsCount - 1]
461 .modification_of_pic_nums_idc == 3);
462 }
463 }
464
465 if (m_curFrameState.FrameType == D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_B_FRAME) {
466
467 // Deep Copy L1 list
468 m_curFrameState.List1ReferenceFramesCount = h264Pic->num_ref_idx_l1_active_minus1 + 1;
469 m_CurrentFrameReferencesData.pList1ReferenceFrames.resize(m_curFrameState.List1ReferenceFramesCount);
470 for (unsigned i = 0; i < m_curFrameState.List1ReferenceFramesCount; i++)
471 m_CurrentFrameReferencesData.pList1ReferenceFrames[i] = h264Pic->ref_list1[i];
472 m_curFrameState.pList1ReferenceFrames = m_CurrentFrameReferencesData.pList1ReferenceFrames.data();
473
474 // Shallow Copy L1 ref modification list
475 m_curFrameState.List1RefPicModificationsCount = h264Pic->slice.num_ref_list1_mod_operations;
476 if (m_curFrameState.List1RefPicModificationsCount > 0) {
477 m_curFrameState.pList1RefPicModifications = reinterpret_cast<
478 D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_H264_REFERENCE_PICTURE_LIST_MODIFICATION_OPERATION *>(
479 &h264Pic->slice.ref_list1_mod_operations[0]);
480 // DX12 driver requires "End modification_of_pic_nums_idc syntax element loop" to be
481 // sent at the end of the list for coding the slice header when sending down reordering commands
482 assert((m_curFrameState.List1RefPicModificationsCount == 0) ||
483 m_curFrameState.pList1RefPicModifications[m_curFrameState.List1RefPicModificationsCount - 1]
484 .modification_of_pic_nums_idc == 3);
485 }
486 }
487
488 print_dpb();
489 print_l0_l1_lists();
490 print_mmco_lists();
491 }
492
493 void
print_mmco_lists()494 d3d12_video_encoder_references_manager_h264::print_mmco_lists()
495 {
496 debug_printf("[D3D12 Video Encoder Picture Manager H264] mmco list (%d entries) for frame with POC "
497 "%d (frame_num: %d) and frame_type %d are:\n",
498 m_curFrameState.RefPicMarkingOperationsCommandsCount,
499 m_curFrameState.PictureOrderCountNumber,
500 m_curFrameState.FrameDecodingOrderNumber,
501 m_curFrameState.FrameType);
502 for (uint32_t idx = 0; idx < m_curFrameState.RefPicMarkingOperationsCommandsCount; idx++) {
503 D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_H264_REFERENCE_PICTURE_MARKING_OPERATION current_op =
504 m_curFrameState.pRefPicMarkingOperationsCommands[idx];
505 switch (current_op.memory_management_control_operation) {
506 case 0:
507 {
508 debug_printf("End memory_management_control_operation syntax element loop\n");
509 } break;
510 case 1:
511 {
512 debug_printf(
513 "Mark a short-term reference picture as \"unused for reference\" - difference_of_pic_nums_minus1: %d\n",
514 current_op.difference_of_pic_nums_minus1);
515 } break;
516 case 2:
517 {
518 debug_printf("Mark a long-term reference picture as \"unused for reference\"\n - long_term_pic_num: %d\n",
519 current_op.long_term_pic_num);
520 } break;
521 case 3:
522 {
523 debug_printf("Mark a short-term reference picture as \"used for long-term reference\" and assign a "
524 "long-term frame index to it - difference_of_pic_nums_minus1: %d - long_term_frame_idx: %d\n",
525 current_op.difference_of_pic_nums_minus1,
526 current_op.long_term_frame_idx);
527 } break;
528 case 4:
529 {
530 debug_printf("Specify the maximum long-term frame index and mark all long-term reference pictures having "
531 "long-term frame indices greater than the maximum value as \"unused for reference\" - "
532 "max_long_term_frame_idx_plus1: %d",
533 current_op.max_long_term_frame_idx_plus1);
534 } break;
535 case 5:
536 {
537 debug_printf("Mark all reference pictures as \"unused for reference\" and set the MaxLongTermFrameIdx "
538 "variable to \"no long-term frame indices\"");
539 } break;
540 case 6:
541 {
542 debug_printf("Mark the current picture as \"used for long-term reference\" and assign a long-term frame "
543 "index to it - long_term_frame_idx: %d",
544 current_op.long_term_frame_idx);
545 } break;
546 default:
547 {
548 unreachable("Unsupported memory_management_control_operation");
549 } break;
550 }
551 }
552 }
553