• 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_encoder_references_manager_hevc.h"
25 #include <algorithm>
26 #include <string>
27 #include "d3d12_screen.h"
28 
29 using namespace std;
30 
d3d12_video_encoder_references_manager_hevc(bool gopHasIorPFrames,d3d12_video_dpb_storage_manager_interface & rDpbStorageManager,uint32_t MaxDPBCapacity)31 d3d12_video_encoder_references_manager_hevc::d3d12_video_encoder_references_manager_hevc(
32    bool gopHasIorPFrames, d3d12_video_dpb_storage_manager_interface &rDpbStorageManager, uint32_t MaxDPBCapacity)
33    : m_MaxDPBCapacity(MaxDPBCapacity),
34      m_rDPBStorageManager(rDpbStorageManager),
35      m_CurrentFrameReferencesData({}),
36      m_gopHasInterFrames(gopHasIorPFrames)
37 {
38    assert((m_MaxDPBCapacity + 1 /*extra for cur frame output recon pic*/) ==
39           m_rDPBStorageManager.get_number_of_tracked_allocations());
40 
41    debug_printf("[D3D12 Video Encoder Picture Manager HEVC] Completed construction of "
42                  "d3d12_video_encoder_references_manager_hevc instance, settings are\n");
43    debug_printf("[D3D12 Video Encoder Picture Manager HEVC] m_MaxDPBCapacity: %d\n", m_MaxDPBCapacity);
44 }
45 
46 void
reset_gop_tracking_and_dpb()47 d3d12_video_encoder_references_manager_hevc::reset_gop_tracking_and_dpb()
48 {
49    // Reset m_CurrentFrameReferencesData tracking
50    m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.clear();
51    m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.reserve(m_MaxDPBCapacity);
52    m_curFrameStateDescriptorStorage.reserve(m_MaxDPBCapacity);
53    m_CurrentFrameReferencesData.ReconstructedPicTexture = { nullptr, 0 };
54 
55    // Reset DPB storage
56    ASSERTED uint32_t numPicsBeforeClearInDPB = m_rDPBStorageManager.get_number_of_pics_in_dpb();
57    ASSERTED uint32_t cFreedResources = m_rDPBStorageManager.clear_decode_picture_buffer();
58    assert(numPicsBeforeClearInDPB == cFreedResources);
59 
60    // Initialize if needed the reconstructed picture allocation for the first IDR picture in the GOP
61    // This needs to be done after initializing the GOP tracking state above since it makes decisions based on the
62    // current picture type.
63    prepare_current_frame_recon_pic_allocation();
64 
65    // After clearing the DPB, outstanding used allocations should be 1u only for the first allocation for the
66    // reconstructed picture of the initial IDR in the GOP
67    assert(m_rDPBStorageManager.get_number_of_in_use_allocations() == (m_gopHasInterFrames ? 1u : 0u));
68    assert(m_rDPBStorageManager.get_number_of_tracked_allocations() <=
69           (m_MaxDPBCapacity + 1));   // pool is not extended beyond maximum expected usage
70 }
71 
72 // Calculates the picture control structure for the current frame
73 bool
get_current_frame_picture_control_data(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA & codecAllocation)74 d3d12_video_encoder_references_manager_hevc::get_current_frame_picture_control_data(
75    D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA &codecAllocation)
76 {
77    // Update reference picture control structures (L0/L1 and DPB descriptors lists based on current frame and next frame
78    // in GOP) for next frame
79 
80    debug_printf("[D3D12 Video Encoder Picture Manager HEVC] %d resources IN USE out of a total of %d ALLOCATED "
81                  "resources at frame with POC: %d\n",
82                  m_rDPBStorageManager.get_number_of_in_use_allocations(),
83                  m_rDPBStorageManager.get_number_of_tracked_allocations(),
84                  m_curFrameState.PictureOrderCountNumber);
85 
86    // See casts below
87    assert(m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.size() < UINT32_MAX);
88 
89    bool needsL0List = (m_curFrameState.FrameType == D3D12_VIDEO_ENCODER_FRAME_TYPE_HEVC_P_FRAME) ||
90                       (m_curFrameState.FrameType == D3D12_VIDEO_ENCODER_FRAME_TYPE_HEVC_B_FRAME);
91    bool needsL1List = (m_curFrameState.FrameType == D3D12_VIDEO_ENCODER_FRAME_TYPE_HEVC_B_FRAME);
92 
93    // (in HEVC I pics might contain following pics, ref not used in curr)
94    bool needsRefPicDescriptors = (m_curFrameState.FrameType != D3D12_VIDEO_ENCODER_FRAME_TYPE_HEVC_IDR_FRAME);
95 
96    assert(codecAllocation.DataSize == sizeof(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC));
97 
98    // See D3D12 Encode spec below
99    // pList0ReferenceFrames
100    //    List of past frame reference frames to be used for this frame. Each integer value in this array indices into
101    //    pReferenceFramesReconPictureDescriptors to reference pictures kept in the DPB.
102    // pList1ReferenceFrames
103    //    List of future frame reference frames to be used for this frame. Each integer value in this array indices into
104    //    pReferenceFramesReconPictureDescriptors to reference pictures kept in the DPB.
105 
106    // Need to map from frame_num in the receiving ref_idx_l0_list/ref_idx_l1_list to the position with that
107    // reference_lists_frame_idx in the DPB descriptor
108 
109    // L0 and L1 need to be ordered by POC (ie. different RefPicSets). The upper layers building the lists should but might not be following this
110 
111    // Set all in the DPB as unused for the current frame, then below just mark as used the ones references by L0 and L1
112    for(UINT idx = 0 ; idx < m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.size() ; idx++)
113    {
114       m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors[idx].base.IsRefUsedByCurrentPic = false;
115    }
116 
117    if (needsL0List && (m_curFrameState.List0ReferenceFramesCount > 0)) {
118       std::vector<uint32_t> tmpL0(m_curFrameState.List0ReferenceFramesCount, 0);
119       memcpy(tmpL0.data(),
120              m_curFrameState.pList0ReferenceFrames,
121              m_curFrameState.List0ReferenceFramesCount * sizeof(m_curFrameState.pList0ReferenceFrames[0]));
122 
123       for (size_t l0Idx = 0; l0Idx < m_curFrameState.List0ReferenceFramesCount; l0Idx++) {
124          // tmpL0[l0Idx] has frame_num's (reference_lists_frame_idx)
125          // m_curFrameState.pList0ReferenceFrames[l0Idx] needs to have the index j of
126          // pReferenceFramesReconPictureDescriptors where
127          // pReferenceFramesReconPictureDescriptors[j].reference_lists_frame_idx == tmpL0[l0Idx]
128 
129          auto value = tmpL0[l0Idx];
130          auto foundItemIt = std::find_if(m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.begin(),
131                                          m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.end(),
132                                          [&value](const D3D12_VIDEO_ENCODER_REFERENCE_PICTURE_DESCRIPTOR_HEVC_EX &p) {
133                                             return p.reference_lists_frame_idx == value;
134                                          });
135 
136          assert(foundItemIt != m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.end());
137          if (foundItemIt == m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.end())
138          {
139             return true;
140          }
141          m_curFrameState.pList0ReferenceFrames[l0Idx] =
142             std::distance(m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.begin(), foundItemIt);
143          m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors[m_curFrameState.pList0ReferenceFrames[l0Idx]].base.IsRefUsedByCurrentPic = true;
144       }
145    }
146 
147    if (needsL1List && (m_curFrameState.List1ReferenceFramesCount > 0)) {
148       std::vector<uint32_t> tmpL1(m_curFrameState.List1ReferenceFramesCount, 0);
149       memcpy(tmpL1.data(),
150              m_curFrameState.pList1ReferenceFrames,
151              m_curFrameState.List1ReferenceFramesCount * sizeof(m_curFrameState.pList1ReferenceFrames[0]));
152 
153       for (size_t l1Idx = 0; l1Idx < m_curFrameState.List1ReferenceFramesCount; l1Idx++) {
154          // tmpL1[l1Idx] has frame_num's (reference_lists_frame_idx)
155          // m_curFrameState.pList1ReferenceFrames[l1Idx] needs to have the index j of
156          // pReferenceFramesReconPictureDescriptors where
157          // pReferenceFramesReconPictureDescriptors[j].reference_lists_frame_idx == tmpL1[l1Idx]
158 
159          auto value = tmpL1[l1Idx];
160          auto foundItemIt = std::find_if(m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.begin(),
161                                          m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.end(),
162                                          [&value](const D3D12_VIDEO_ENCODER_REFERENCE_PICTURE_DESCRIPTOR_HEVC_EX &p) {
163                                             return p.reference_lists_frame_idx == value;
164                                          });
165 
166          assert(foundItemIt != m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.end());
167          if (foundItemIt == m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.end())
168          {
169             return true;
170          }
171          m_curFrameState.pList1ReferenceFrames[l1Idx] =
172             std::distance(m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.begin(), foundItemIt);
173          m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors[m_curFrameState.pList1ReferenceFrames[l1Idx]].base.IsRefUsedByCurrentPic = true;
174       }
175    }
176 
177    m_curFrameState.List0ReferenceFramesCount = needsL0List ? m_curFrameState.List0ReferenceFramesCount : 0;
178    m_curFrameState.pList0ReferenceFrames = needsL0List ? m_curFrameState.pList0ReferenceFrames : nullptr,
179    m_curFrameState.List1ReferenceFramesCount = needsL1List ? m_curFrameState.List1ReferenceFramesCount : 0,
180    m_curFrameState.pList1ReferenceFrames = needsL1List ? m_curFrameState.pList1ReferenceFrames : nullptr;
181 
182    if (!needsRefPicDescriptors) {
183       m_curFrameState.ReferenceFramesReconPictureDescriptorsCount = 0;
184       m_curFrameState.pReferenceFramesReconPictureDescriptors = nullptr;
185    } else {
186       m_curFrameState.ReferenceFramesReconPictureDescriptorsCount = static_cast<uint32_t>(m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.size());
187       m_curFrameStateDescriptorStorage.resize(m_curFrameState.ReferenceFramesReconPictureDescriptorsCount);
188       for(uint32_t idx = 0; idx < m_curFrameState.ReferenceFramesReconPictureDescriptorsCount ; idx++) {
189          m_curFrameStateDescriptorStorage[idx] = m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors[idx].base;
190       }
191       m_curFrameState.pReferenceFramesReconPictureDescriptors = m_curFrameStateDescriptorStorage.data();
192    }
193 
194    *codecAllocation.pHEVCPicData = m_curFrameState;
195 
196    print_l0_l1_lists();
197    print_dpb();
198    return true;
199 }
200 
201 // Returns the resource allocation for a reconstructed picture output for the current frame
202 D3D12_VIDEO_ENCODER_RECONSTRUCTED_PICTURE
get_current_frame_recon_pic_output_allocation()203 d3d12_video_encoder_references_manager_hevc::get_current_frame_recon_pic_output_allocation()
204 {
205    return m_CurrentFrameReferencesData.ReconstructedPicTexture;
206 }
207 
208 D3D12_VIDEO_ENCODE_REFERENCE_FRAMES
get_current_reference_frames()209 d3d12_video_encoder_references_manager_hevc::get_current_reference_frames()
210 {
211    D3D12_VIDEO_ENCODE_REFERENCE_FRAMES retVal = { 0,
212                                                   // ppTexture2Ds
213                                                   nullptr,
214                                                   // pSubresources
215                                                   nullptr };
216 
217    // Return nullptr for fully intra frames (eg IDR)
218    // and return references information for inter frames (eg.P/B) and I frame that doesn't flush DPB
219 
220    if ((m_curFrameState.FrameType != D3D12_VIDEO_ENCODER_FRAME_TYPE_HEVC_IDR_FRAME) && m_gopHasInterFrames) {
221       auto curRef = m_rDPBStorageManager.get_current_reference_frames();
222       retVal.NumTexture2Ds = curRef.NumTexture2Ds;
223       retVal.ppTexture2Ds = curRef.ppTexture2Ds;
224       retVal.pSubresources = curRef.pSubresources;
225    }
226 
227    return retVal;
228 }
229 
230 void
prepare_current_frame_recon_pic_allocation()231 d3d12_video_encoder_references_manager_hevc::prepare_current_frame_recon_pic_allocation()
232 {
233    m_CurrentFrameReferencesData.ReconstructedPicTexture = { nullptr, 0 };
234 
235    // If all GOP are intra frames, no point in doing reference pic allocations
236    if (is_current_frame_used_as_reference() && m_gopHasInterFrames) {
237       auto reconPic = m_rDPBStorageManager.get_new_tracked_picture_allocation();
238       m_CurrentFrameReferencesData.ReconstructedPicTexture.pReconstructedPicture = reconPic.pReconstructedPicture;
239       m_CurrentFrameReferencesData.ReconstructedPicTexture.ReconstructedPictureSubresource =
240          reconPic.ReconstructedPictureSubresource;
241    }
242 }
243 
244 void
update_fifo_dpb_push_front_cur_recon_pic()245 d3d12_video_encoder_references_manager_hevc::update_fifo_dpb_push_front_cur_recon_pic()
246 {
247    // Keep the order of the dpb storage and dpb descriptors in a circular buffer
248    // order such that the DPB array consists of a sequence of frames in DECREASING encoding order
249    // eg. last frame encoded at first, followed by one to last frames encoded, and at the end
250    // the most distant frame encoded (currentFrameEncodeOrderNumber - MaxDPBSize)
251 
252    // If current pic was not used as reference, current reconstructed picture resource is empty,
253    // No need to to anything in that case.
254    // Otherwise extract the reconstructed picture result and add it to the DPB
255 
256    // If GOP are all intra frames, do nothing also.
257    if (is_current_frame_used_as_reference() && m_gopHasInterFrames) {
258       debug_printf("[D3D12 Video Encoder Picture Manager HEVC] MaxDPBCapacity is %d - Number of pics in DPB is %d "
259                     "when trying to put frame with POC %d (frame_num %d) at front of the DPB\n",
260                     m_MaxDPBCapacity,
261                     m_rDPBStorageManager.get_number_of_pics_in_dpb(),
262                     m_curFrameState.PictureOrderCountNumber,
263                     m_current_frame_idx);
264 
265       // Release least recently used in DPB if we filled the m_MaxDPBCapacity allowed
266       if (m_rDPBStorageManager.get_number_of_pics_in_dpb() == m_MaxDPBCapacity) {
267          bool untrackedRes = false;
268          m_rDPBStorageManager.remove_reference_frame(m_rDPBStorageManager.get_number_of_pics_in_dpb() - 1,
269                                                      &untrackedRes);   // Remove last entry
270          // Verify that resource was untracked since this class is using the pool completely for allocations
271          assert(untrackedRes);
272          m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.pop_back();   // Remove last entry
273       }
274 
275       // Add new dpb to front of DPB
276       D3D12_VIDEO_ENCODER_RECONSTRUCTED_PICTURE recAlloc = get_current_frame_recon_pic_output_allocation();
277       d3d12_video_reconstructed_picture refFrameDesc = {};
278       refFrameDesc.pReconstructedPicture = recAlloc.pReconstructedPicture;
279       refFrameDesc.ReconstructedPictureSubresource = recAlloc.ReconstructedPictureSubresource;
280       refFrameDesc.pVideoHeap = nullptr;   // D3D12 Video Encode does not need the D3D12VideoEncoderHeap struct for HEVC
281                                            // (used for no-key-frame resolution change in VC1, AV1, etc)
282       m_rDPBStorageManager.insert_reference_frame(refFrameDesc, 0);
283 
284       // Prepare D3D12_VIDEO_ENCODER_REFERENCE_PICTURE_DESCRIPTOR_HEVC_EX for added DPB member
285       D3D12_VIDEO_ENCODER_REFERENCE_PICTURE_DESCRIPTOR_HEVC_EX newDPBDescriptor =
286       {
287          // D3D12_VIDEO_ENCODER_REFERENCE_PICTURE_DESCRIPTOR_HEVC
288          {
289             // UINT ReconstructedPictureResourceIndex;
290             0, // the associated reconstructed picture is also being pushed_front in m_rDPBStorageManager
291             // BOOL IsRefUsedByCurrentPic;
292             false, // usage is determined in method AdvanceFrame according to picture type to be encoded
293             // BOOL IsLongTermReference
294             false, // not implemented - neither FFMPEG or GSTREAMER use LTR for HEVC VAAPI
295             // UINT PictureOrderCountNumber;
296             m_curFrameState.PictureOrderCountNumber,
297             // UINT TemporalLayerIndex;
298             0
299          },
300          // reference_lists_frame_idx
301          m_current_frame_idx,
302       };
303 
304       // Add DPB entry
305       m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.insert(
306          m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.begin(),
307          newDPBDescriptor);
308 
309       // Update the indices for ReconstructedPictureResourceIndex in pReferenceFramesReconPictureDescriptors
310       // to be in identity mapping with m_rDPBStorageManager indices
311       // after pushing the elements to the right in the push_front operation
312       for (uint32_t dpbResIdx = 1;
313            dpbResIdx < m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.size();
314            dpbResIdx++) {
315          auto &dpbDesc = m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors[dpbResIdx];
316          dpbDesc.base.ReconstructedPictureResourceIndex = dpbResIdx;
317       }
318    }
319 
320    // Number of allocations, disregarding if they are used or not, should not exceed this limit due to reuse policies on
321    // DPB items removal.
322    assert(m_rDPBStorageManager.get_number_of_tracked_allocations() <= (m_MaxDPBCapacity + 1));
323 }
324 
325 void
print_l0_l1_lists()326 d3d12_video_encoder_references_manager_hevc::print_l0_l1_lists()
327 {
328    if ((D3D12_DEBUG_VERBOSE & d3d12_debug) &&
329        ((m_curFrameState.FrameType == D3D12_VIDEO_ENCODER_FRAME_TYPE_HEVC_P_FRAME) ||
330         (m_curFrameState.FrameType == D3D12_VIDEO_ENCODER_FRAME_TYPE_HEVC_B_FRAME))) {
331       std::string list0ContentsString;
332       for (uint32_t idx = 0; idx < m_curFrameState.List0ReferenceFramesCount; idx++) {
333          uint32_t value = m_curFrameState.pList0ReferenceFrames[idx];
334          list0ContentsString += "{ DPBidx: ";
335          list0ContentsString += std::to_string(value);
336          list0ContentsString += " - POC: ";
337          list0ContentsString += std::to_string(
338             m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors[value].base.PictureOrderCountNumber);
339          list0ContentsString += " - IsRefUsedByCurrentPic: ";
340          list0ContentsString += std::to_string(
341             m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors[value].base.IsRefUsedByCurrentPic);
342          list0ContentsString += " - IsLongTermReference: ";
343          list0ContentsString += std::to_string(
344             m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors[value].base.IsLongTermReference);
345          list0ContentsString += " - reference_lists_frame_idx: ";
346          list0ContentsString += std::to_string(
347             m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors[value].reference_lists_frame_idx);
348          list0ContentsString += "}\n";
349       }
350 
351       debug_printf(
352          "[D3D12 Video Encoder Picture Manager HEVC] L0 list for frame with POC %d (frame_num %d) is: \n %s \n",
353          m_curFrameState.PictureOrderCountNumber,
354          m_current_frame_idx,
355          list0ContentsString.c_str());
356 
357       std::string list1ContentsString;
358       for (uint32_t idx = 0; idx < m_curFrameState.List1ReferenceFramesCount; idx++) {
359          uint32_t value = m_curFrameState.pList1ReferenceFrames[idx];
360          list1ContentsString += "{ DPBidx: ";
361          list1ContentsString += std::to_string(value);
362          list1ContentsString += " - POC: ";
363          list1ContentsString += std::to_string(
364             m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors[value].base.PictureOrderCountNumber);
365          list1ContentsString += " - IsRefUsedByCurrentPic: ";
366          list1ContentsString += std::to_string(
367             m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors[value].base.IsRefUsedByCurrentPic);
368          list1ContentsString += " - IsLongTermReference: ";
369          list1ContentsString += std::to_string(
370             m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors[value].base.IsLongTermReference);
371          list1ContentsString += " - reference_lists_frame_idx: ";
372          list1ContentsString += std::to_string(
373             m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors[value].reference_lists_frame_idx);
374          list1ContentsString += "}\n";
375       }
376 
377       debug_printf(
378          "[D3D12 Video Encoder Picture Manager HEVC] L1 list for frame with POC %d (frame_num %d) is: \n %s \n",
379          m_curFrameState.PictureOrderCountNumber,
380          m_current_frame_idx,
381          list1ContentsString.c_str());
382    }
383 }
384 
385 void
print_dpb()386 d3d12_video_encoder_references_manager_hevc::print_dpb()
387 {
388    if (D3D12_DEBUG_VERBOSE & d3d12_debug) {
389       std::string dpbContents;
390       for (uint32_t dpbResIdx = 0;
391            dpbResIdx < m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.size();
392            dpbResIdx++) {
393          auto &dpbDesc = m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors[dpbResIdx];
394          auto dpbEntry = m_rDPBStorageManager.get_reference_frame(dpbDesc.base.ReconstructedPictureResourceIndex);
395 
396          dpbContents += "{ DPBidx: ";
397          dpbContents += std::to_string(dpbResIdx);
398          dpbContents += " - POC: ";
399          dpbContents += std::to_string(dpbDesc.base.PictureOrderCountNumber);
400          dpbContents += " - IsRefUsedByCurrentPic: ";
401          dpbContents += std::to_string(dpbDesc.base.IsRefUsedByCurrentPic);
402          dpbContents += " - DPBStorageIdx: ";
403          dpbContents += std::to_string(dpbDesc.base.ReconstructedPictureResourceIndex);
404          dpbContents += " - reference_lists_frame_idx: ";
405          dpbContents += std::to_string(dpbDesc.reference_lists_frame_idx);
406          dpbContents += " - DPBStorageResourcePtr: ";
407          char strBuf[256];
408          memset(&strBuf, '\0', 256);
409          sprintf(strBuf, "%p", dpbEntry.pReconstructedPicture);
410          dpbContents += std::string(strBuf);
411          dpbContents += " - DPBStorageSubresource: ";
412          dpbContents += std::to_string(dpbEntry.ReconstructedPictureSubresource);
413          dpbContents += "}\n";
414       }
415 
416       debug_printf("[D3D12 Video Encoder Picture Manager HEVC] DPB has %d frames - DPB references for frame with POC "
417                     "%d are: \n %s \n",
418                     m_rDPBStorageManager.get_number_of_pics_in_dpb(),
419                     m_curFrameState.PictureOrderCountNumber,
420                     dpbContents.c_str());
421    }
422 }
423 
424 // Advances state to next frame in GOP; subsequent calls to GetCurrentFrame* point to the advanced frame status
425 void
end_frame()426 d3d12_video_encoder_references_manager_hevc::end_frame()
427 {
428    debug_printf("[D3D12 Video Encoder Picture Manager HEVC] %d resources IN USE out of a total of %d ALLOCATED "
429                  "resources at end_frame for frame with POC: %d\n",
430                  m_rDPBStorageManager.get_number_of_in_use_allocations(),
431                  m_rDPBStorageManager.get_number_of_tracked_allocations(),
432                  m_curFrameState.PictureOrderCountNumber);
433 
434    // Adds last used (if not null) get_current_frame_recon_pic_output_allocation to DPB for next EncodeFrame if
435    // necessary updates pReferenceFramesReconPictureDescriptors and updates the dpb storage
436 
437    update_fifo_dpb_push_front_cur_recon_pic();
438 }
439 
440 bool
is_current_frame_used_as_reference()441 d3d12_video_encoder_references_manager_hevc::is_current_frame_used_as_reference()
442 {
443    return m_isCurrentFrameUsedAsReference;
444 }
445 
446 void
begin_frame(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA curFrameData,bool bUsedAsReference,struct pipe_picture_desc * picture)447 d3d12_video_encoder_references_manager_hevc::begin_frame(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA curFrameData,
448                                                          bool bUsedAsReference, struct pipe_picture_desc* picture)
449 {
450    pipe_h265_enc_picture_desc * pPipeDesc = (pipe_h265_enc_picture_desc*) picture;
451 
452    m_curFrameState = *curFrameData.pHEVCPicData;
453    m_isCurrentFrameUsedAsReference = bUsedAsReference;
454    m_current_frame_idx = pPipeDesc->frame_num;
455    debug_printf("Marking POC %d (frame_num %d) as reference ? %d\n",
456                  curFrameData.pHEVCPicData->PictureOrderCountNumber,
457                  m_current_frame_idx,
458                  bUsedAsReference);
459 
460    // Advance the GOP tracking state
461    bool isDPBFlushNeeded = (m_curFrameState.FrameType == D3D12_VIDEO_ENCODER_FRAME_TYPE_HEVC_IDR_FRAME);
462    if (isDPBFlushNeeded) {
463       reset_gop_tracking_and_dpb();
464    } else {
465       // Get new allocation from DPB storage for reconstructed picture
466       // This is only necessary for the frames that come after an IDR
467       // since in the initial state already has this initialized
468       // and re-initialized by reset_gop_tracking_and_dpb above
469 
470       prepare_current_frame_recon_pic_allocation();
471    }
472 }
473