xref: /aosp_15_r20/external/mesa3d/src/gallium/drivers/d3d12/d3d12_video_texture_array_dpb_manager.cpp (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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_texture_array_dpb_manager.h"
25 
26 #include "d3d12_common.h"
27 
28 #include "d3d12_util.h"
29 
30 ///
31 /// d3d12_texture_array_dpb_manager
32 ///
33 
34 // Differences with ArrayOfTextures
35 // Uses a D3D12 Texture Array instead of an std::vector with individual D3D resources as backing storage
36 // Doesn't support extension (by reallocation and copy) of the pool
37 
38 void
create_reconstructed_picture_allocations(ID3D12Resource ** ppResource,uint16_t texArraySize)39 d3d12_texture_array_dpb_manager::create_reconstructed_picture_allocations(ID3D12Resource **ppResource,
40                                                                           uint16_t         texArraySize)
41 {
42    if (texArraySize > 0) {
43       D3D12_HEAP_PROPERTIES Properties = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT, m_nodeMask, m_nodeMask);
44       CD3DX12_RESOURCE_DESC reconstructedPictureResourceDesc = CD3DX12_RESOURCE_DESC::Tex2D(m_encodeFormat,
45                                                                                             m_encodeResolution.Width,
46                                                                                             m_encodeResolution.Height,
47                                                                                             texArraySize,
48                                                                                             1,
49                                                                                             1,
50                                                                                             0,
51                                                                                             m_resourceAllocFlags);
52 
53       HRESULT hr = m_pDevice->CreateCommittedResource(&Properties,
54                                                           D3D12_HEAP_FLAG_NONE,
55                                                           &reconstructedPictureResourceDesc,
56                                                           D3D12_RESOURCE_STATE_COMMON,
57                                                           nullptr,
58                                                           IID_PPV_ARGS(ppResource));
59       if (FAILED(hr)) {
60          debug_printf("CreateCommittedResource failed with HR %x\n", hr);
61          assert(false);
62       }
63    }
64 }
65 
~d3d12_texture_array_dpb_manager()66 d3d12_texture_array_dpb_manager::~d3d12_texture_array_dpb_manager()
67 { }
68 
d3d12_texture_array_dpb_manager(uint16_t dpbTextureArraySize,ID3D12Device * pDevice,DXGI_FORMAT encodeSessionFormat,D3D12_VIDEO_ENCODER_PICTURE_RESOLUTION_DESC encodeSessionResolution,D3D12_RESOURCE_FLAGS resourceAllocFlags,uint32_t nodeMask)69 d3d12_texture_array_dpb_manager::d3d12_texture_array_dpb_manager(
70    uint16_t                                    dpbTextureArraySize,
71    ID3D12Device *                              pDevice,
72    DXGI_FORMAT                                 encodeSessionFormat,
73    D3D12_VIDEO_ENCODER_PICTURE_RESOLUTION_DESC encodeSessionResolution,
74    D3D12_RESOURCE_FLAGS                        resourceAllocFlags,
75    uint32_t                                    nodeMask)
76    : m_pDevice(pDevice),
77      m_encodeFormat(encodeSessionFormat),
78      m_encodeResolution(encodeSessionResolution),
79      m_dpbTextureArraySize(dpbTextureArraySize),
80      m_resourceAllocFlags(resourceAllocFlags),
81      m_nodeMask(nodeMask)
82 {
83    // Initialize D3D12 DPB exposed in this class implemented CRUD interface for a DPB
84    clear_decode_picture_buffer();
85 
86    // Implement a reusable pool of D3D12 Resources as an array of textures
87    uint16_t poolFixedSize = m_dpbTextureArraySize;
88    m_ResourcesPool.resize(poolFixedSize);
89 
90    // Build resource pool with commitedresources with a d3ddevice and the encoding session settings (eg. resolution) and
91    // the reference_only flag
92    create_reconstructed_picture_allocations(m_baseTexArrayResource.GetAddressOf(), poolFixedSize);
93 
94    for (uint32_t idxSubres = 0; idxSubres < poolFixedSize; idxSubres++) {
95       m_ResourcesPool[idxSubres].pResource   = m_baseTexArrayResource;
96       m_ResourcesPool[idxSubres].subresource = idxSubres;
97       m_ResourcesPool[idxSubres].isFree      = true;
98    }
99 }
100 
101 uint32_t
clear_decode_picture_buffer()102 d3d12_texture_array_dpb_manager::clear_decode_picture_buffer()
103 {
104    assert(m_D3D12DPB.pResources.size() == m_D3D12DPB.pSubresources.size());
105 
106    uint32_t untrackCount = 0;
107    // Mark resources used in DPB as re-usable in the resources pool
108    for (uint32_t idx = 0; idx < m_D3D12DPB.pResources.size(); idx++) {
109       // Don't assert the untracking result here in case the DPB contains resources not adquired using the pool methods
110       // in this interface
111       untrackCount +=
112          untrack_reconstructed_picture_allocation({ m_D3D12DPB.pResources[idx], m_D3D12DPB.pSubresources[idx] }) ? 1 :
113                                                                                                                    0;
114    }
115 
116    // Clear DPB
117    m_D3D12DPB.pResources.clear();
118    m_D3D12DPB.pSubresources.clear();
119    m_D3D12DPB.pHeaps.clear();
120    m_D3D12DPB.pResources.reserve(m_dpbTextureArraySize);
121    m_D3D12DPB.pSubresources.reserve(m_dpbTextureArraySize);
122    m_D3D12DPB.pHeaps.reserve(m_dpbTextureArraySize);
123 
124    return untrackCount;
125 }
126 
127 // Assigns a reference frame at a given position
128 void
assign_reference_frame(d3d12_video_reconstructed_picture pReconPicture,uint32_t dpbPosition)129 d3d12_texture_array_dpb_manager::assign_reference_frame(d3d12_video_reconstructed_picture pReconPicture,
130                                                         uint32_t                          dpbPosition)
131 {
132    assert(m_D3D12DPB.pResources.size() == m_D3D12DPB.pSubresources.size());
133    assert(m_D3D12DPB.pResources.size() == m_D3D12DPB.pHeaps.size());
134 
135    assert(dpbPosition < m_D3D12DPB.pResources.size());
136 
137    m_D3D12DPB.pResources[dpbPosition]    = pReconPicture.pReconstructedPicture;
138    m_D3D12DPB.pSubresources[dpbPosition] = pReconPicture.ReconstructedPictureSubresource;
139    m_D3D12DPB.pHeaps[dpbPosition]        = pReconPicture.pVideoHeap;
140 }
141 
142 // Adds a new reference frame at a given position
143 void
insert_reference_frame(d3d12_video_reconstructed_picture pReconPicture,uint32_t dpbPosition)144 d3d12_texture_array_dpb_manager::insert_reference_frame(d3d12_video_reconstructed_picture pReconPicture,
145                                                         uint32_t                          dpbPosition)
146 {
147    assert(m_D3D12DPB.pResources.size() == m_D3D12DPB.pSubresources.size());
148    assert(m_D3D12DPB.pResources.size() == m_D3D12DPB.pHeaps.size());
149 
150    if (dpbPosition > m_D3D12DPB.pResources.size()) {
151       // extend capacity
152       m_D3D12DPB.pResources.resize(dpbPosition);
153       m_D3D12DPB.pSubresources.resize(dpbPosition);
154       m_D3D12DPB.pHeaps.resize(dpbPosition);
155    }
156 
157    m_D3D12DPB.pResources.insert(m_D3D12DPB.pResources.begin() + dpbPosition, pReconPicture.pReconstructedPicture);
158    m_D3D12DPB.pSubresources.insert(m_D3D12DPB.pSubresources.begin() + dpbPosition,
159                                    pReconPicture.ReconstructedPictureSubresource);
160    m_D3D12DPB.pHeaps.insert(m_D3D12DPB.pHeaps.begin() + dpbPosition, pReconPicture.pVideoHeap);
161 }
162 
163 // Gets a reference frame at a given position
164 d3d12_video_reconstructed_picture
get_reference_frame(uint32_t dpbPosition)165 d3d12_texture_array_dpb_manager::get_reference_frame(uint32_t dpbPosition)
166 {
167    assert(dpbPosition < m_D3D12DPB.pResources.size());
168 
169    d3d12_video_reconstructed_picture retVal = { m_D3D12DPB.pResources[dpbPosition],
170                                                 m_D3D12DPB.pSubresources[dpbPosition],
171                                                 m_D3D12DPB.pHeaps[dpbPosition] };
172 
173    return retVal;
174 }
175 
176 // Removes a new reference frame at a given position and returns operation success
177 bool
remove_reference_frame(uint32_t dpbPosition,bool * pResourceUntracked)178 d3d12_texture_array_dpb_manager::remove_reference_frame(uint32_t dpbPosition, bool *pResourceUntracked)
179 {
180    assert(m_D3D12DPB.pResources.size() == m_D3D12DPB.pSubresources.size());
181    assert(m_D3D12DPB.pResources.size() == m_D3D12DPB.pHeaps.size());
182 
183    assert(dpbPosition < m_D3D12DPB.pResources.size());
184 
185    // If removed resource came from resource pool, mark it as free
186    // to free it for a new usage
187    // Don't assert the untracking result here in case the DPB contains resources not adquired using the pool methods in
188    // this interface
189    bool resUntracked = untrack_reconstructed_picture_allocation(
190       { m_D3D12DPB.pResources[dpbPosition], m_D3D12DPB.pSubresources[dpbPosition] });
191 
192    if (pResourceUntracked != nullptr) {
193       *pResourceUntracked = resUntracked;
194    }
195 
196    // Remove from DPB tables
197    m_D3D12DPB.pResources.erase(m_D3D12DPB.pResources.begin() + dpbPosition);
198    m_D3D12DPB.pSubresources.erase(m_D3D12DPB.pSubresources.begin() + dpbPosition);
199    m_D3D12DPB.pHeaps.erase(m_D3D12DPB.pHeaps.begin() + dpbPosition);
200 
201    return true;
202 }
203 
204 // Returns true if the trackedItem was allocated (and is being tracked) by this class
205 bool
is_tracked_allocation(d3d12_video_reconstructed_picture trackedItem)206 d3d12_texture_array_dpb_manager::is_tracked_allocation(d3d12_video_reconstructed_picture trackedItem)
207 {
208    for (auto &reusableRes : m_ResourcesPool) {
209       if ((trackedItem.pReconstructedPicture == reusableRes.pResource.Get()) &&
210           (trackedItem.ReconstructedPictureSubresource == reusableRes.subresource) && !reusableRes.isFree) {
211          return true;
212       }
213    }
214    return false;
215 }
216 
217 // Returns whether it found the tracked resource on this instance pool tracking and was able to free it
218 bool
untrack_reconstructed_picture_allocation(d3d12_video_reconstructed_picture trackedItem)219 d3d12_texture_array_dpb_manager::untrack_reconstructed_picture_allocation(d3d12_video_reconstructed_picture trackedItem)
220 {
221    for (auto &reusableRes : m_ResourcesPool) {
222       if ((trackedItem.pReconstructedPicture == reusableRes.pResource.Get()) &&
223           (trackedItem.ReconstructedPictureSubresource == reusableRes.subresource)) {
224          reusableRes.isFree = true;
225          return true;
226       }
227    }
228    return false;
229 }
230 
231 // Returns a fresh resource for a NEW picture to be written to
232 // this class implements the dpb allocations as an array of textures
233 d3d12_video_reconstructed_picture
get_new_tracked_picture_allocation()234 d3d12_texture_array_dpb_manager::get_new_tracked_picture_allocation()
235 {
236    d3d12_video_reconstructed_picture freshAllocation = { // pResource
237                                                          nullptr,
238                                                          // subresource
239                                                          0
240    };
241 
242    // Find first (if any) available resource to (re-)use
243    bool bAvailableResourceInPool = false;
244    for (auto &reusableRes : m_ResourcesPool) {
245       if (reusableRes.isFree) {
246          bAvailableResourceInPool                        = true;
247          freshAllocation.pReconstructedPicture           = reusableRes.pResource.Get();
248          freshAllocation.ReconstructedPictureSubresource = reusableRes.subresource;
249          reusableRes.isFree                              = false;
250          break;
251       }
252    }
253 
254    if (!bAvailableResourceInPool) {
255       debug_printf("[d3d12_texture_array_dpb_manager] ID3D12Resource pool is full - Pool capacity (%" PRIu32 ") - Returning null allocation",
256                       static_cast<uint32_t>(m_ResourcesPool.size()));
257    }
258 
259    return freshAllocation;
260 }
261 
262 uint32_t
get_number_of_pics_in_dpb()263 d3d12_texture_array_dpb_manager::get_number_of_pics_in_dpb()
264 {
265    assert(m_D3D12DPB.pResources.size() == m_D3D12DPB.pSubresources.size());
266    assert(m_D3D12DPB.pResources.size() == m_D3D12DPB.pHeaps.size());
267    assert(m_D3D12DPB.pResources.size() < UINT32_MAX);
268    return static_cast<uint32_t>(m_D3D12DPB.pResources.size());
269 }
270 
271 d3d12_video_reference_frames
get_current_reference_frames()272 d3d12_texture_array_dpb_manager::get_current_reference_frames()
273 {
274    d3d12_video_reference_frames retVal = {
275       get_number_of_pics_in_dpb(),
276       m_D3D12DPB.pResources.data(),
277       m_D3D12DPB.pSubresources.data(),
278       m_D3D12DPB.pHeaps.data(),
279    };
280 
281    return retVal;
282 }
283 
284 // number of resources in the pool that are marked as in use
285 uint32_t
get_number_of_in_use_allocations()286 d3d12_texture_array_dpb_manager::get_number_of_in_use_allocations()
287 {
288    uint32_t countOfInUseResourcesInPool = 0;
289    for (auto &reusableRes : m_ResourcesPool) {
290       if (!reusableRes.isFree) {
291          countOfInUseResourcesInPool++;
292       }
293    }
294    return countOfInUseResourcesInPool;
295 }
296 
297 // Returns the number of pictures currently stored in the DPB
298 uint32_t
get_number_of_tracked_allocations()299 d3d12_texture_array_dpb_manager::get_number_of_tracked_allocations()
300 {
301    assert(m_ResourcesPool.size() < UINT32_MAX);
302    return static_cast<uint32_t>(m_ResourcesPool.size());
303 }
304