xref: /aosp_15_r20/external/mesa3d/src/gallium/drivers/d3d12/d3d12_video_dec_references_mgr.h (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 #ifndef D3D12_VIDEO_DEC_REFMGR_H
25 #define D3D12_VIDEO_DEC_REFMGR_H
26 
27 #include "d3d12_video_types.h"
28 #include "d3d12_video_dpb_storage_manager.h"
29 #include "d3d12_util.h"
30 #include <algorithm>
31 #include <map>
32 
33 struct d3d12_video_decoder_references_manager
34 {
35    d3d12_video_decoder_references_manager(const struct d3d12_screen *       pD3D12Screen,
36                                           uint32_t                          NodeMask,
37                                           d3d12_video_decode_profile_type   DecodeProfileType,
38                                           d3d12_video_decode_dpb_descriptor dpbDescriptor);
39 
is_reference_onlyd3d12_video_decoder_references_manager40    bool is_reference_only()
41    {
42       return m_dpbDescriptor.fReferenceOnly;
43    }
is_array_of_texturesd3d12_video_decoder_references_manager44    bool is_array_of_textures()
45    {
46       return m_dpbDescriptor.fArrayOfTexture;
47    }
48 
is_pipe_buffer_underlying_output_decode_allocationd3d12_video_decoder_references_manager49    bool is_pipe_buffer_underlying_output_decode_allocation()
50    {
51       return (is_reference_only() || is_array_of_textures());
52    }
53 
54    void mark_all_references_as_unused();
55    void release_unused_references_texture_memory();
56 
57    template <typename T, size_t size>
58    void mark_references_in_use(const T (&picEntries)[size]);
59    template <typename T, size_t size>
60    void mark_references_in_use_av1(const T (&picEntries)[size]);
61    void mark_reference_in_use(uint16_t index);
62 
63    uint16_t store_future_reference(uint16_t index,
64                                    _In_ ComPtr<ID3D12VideoDecoderHeap> &decoderHeap,
65                                    ID3D12Resource *                     pTexture2D,
66                                    uint32_t                             subresourceIndex);
67 
68    // Will clear() argument outNeededTransitions and fill it with the necessary transitions to perform by the caller
69    // after the method returns
70    template <typename T, size_t size>
71    void update_entries(T (&picEntries)[size], std::vector<D3D12_RESOURCE_BARRIER> &outNeededTransitions);
72 
73    template <typename T, size_t size>
74    void update_entries_av1(T (&picEntries)[size], std::vector<D3D12_RESOURCE_BARRIER> &outNeededTransitions);
75 
76    void get_reference_only_output(
77       struct pipe_video_buffer *  pCurrentDecodeTarget,
78       ID3D12Resource **ppOutputReference,     // out -> new reference slot assigned or nullptr
79       uint32_t *       pOutputSubresource,    // out -> new reference slot assigned or nullptr
80       bool &outNeedsTransitionToDecodeWrite   // out -> indicates if output resource argument has to be transitioned to
81                                               // D3D12_RESOURCE_STATE_VIDEO_DECODE_WRITE by the caller
82    );
83 
84    // Gets the output texture for the current frame to be decoded
85    void get_current_frame_decode_output_texture(struct pipe_video_buffer *pCurrentDecodeTarget, ID3D12Resource **ppOutTexture2D, uint32_t *pOutSubresourceIndex);
86 
87    D3D12_VIDEO_DECODE_REFERENCE_FRAMES get_current_reference_frames();
88 
89    void print_dpb();
90 
get_unused_index7bitsd3d12_video_decoder_references_manager91    uint8_t get_unused_index7bits()
92    {
93       for (uint32_t testIdx = 0; testIdx < 127; testIdx++) {
94          auto it = std::find_if(m_DecodeTargetToOriginalIndex7Bits.begin(), m_DecodeTargetToOriginalIndex7Bits.end(),
95             [&testIdx](const std::pair< struct pipe_video_buffer*, uint8_t > &p) {
96                return p.second == testIdx;
97             });
98 
99          if (it == m_DecodeTargetToOriginalIndex7Bits.end())
100             return testIdx;
101       }
102       debug_printf(
103          "[d3d12_video_decoder_references_manager] d3d12_video_decoder_references_manager - Decode - No available "
104          "fresh indices left.\n");
105       assert(false);
106       return 0;
107    }
108 
109    ///
110    /// Get the Index7Bits associated with this decode target
111    /// If there isn't one assigned yet, gives out a fresh/unused Index7Bits
112    ///
get_index7bitsd3d12_video_decoder_references_manager113    uint8_t get_index7bits(struct pipe_video_buffer * pDecodeTarget) {
114       if(m_DecodeTargetToOriginalIndex7Bits.count(pDecodeTarget) == 0)
115          m_DecodeTargetToOriginalIndex7Bits[pDecodeTarget] = get_unused_index7bits();
116       return m_DecodeTargetToOriginalIndex7Bits[pDecodeTarget];
117    }
118 
119  private:
120    uint16_t update_entry(
121       uint16_t         index,                // in
122       ID3D12Resource *&pOutputReference,     // out -> new reference slot assigned or nullptr
123       uint32_t &       OutputSubresource,    // out -> new reference slot assigned or 0
124       bool &outNeedsTransitionToDecodeRead   // out -> indicates if output resource argument has to be transitioned to
125                                              // D3D12_RESOURCE_STATE_VIDEO_DECODE_READ by the caller
126    );
127 
128    uint16_t find_remapped_index(uint16_t originalIndex);
129 
130    struct ReferenceData
131    {
132       uint16_t originalIndex;
133       bool     fUsed;
134    };
135 
136    // Holds the DPB textures
137    std::unique_ptr<d3d12_video_dpb_storage_manager_interface> m_upD3D12TexturesStorageManager;
138    std::vector<ID3D12VideoDecoderHeap *>
139       m_ppHeaps;   // Auxiliary allocation to QueryInterface the IUnknown's
140                    // m_upD3D12TexturesStorageManager->get_current_reference_frames().ppHeaps
141                    // containing the generic video encode/decode heap;
142 
143    // Holds the mapping between DXVA PicParams indices and the D3D12 indices
144    std::vector<ReferenceData> m_referenceDXVAIndices;
145 
146    std::map<struct pipe_video_buffer *, uint8_t> m_DecodeTargetToOriginalIndex7Bits = { };
147 
148    const struct d3d12_screen *       m_pD3D12Screen;
149    uint16_t                          m_invalidIndex;
150    d3d12_video_decode_dpb_descriptor m_dpbDescriptor      = {};
151    uint16_t                          m_currentOutputIndex = 0;
152    uint16_t                          m_currentSubresourceIndex = 0;
153    ID3D12Resource*                   m_currentResource = nullptr;
154    D3D12_FEATURE_DATA_FORMAT_INFO    m_formatInfo         = { m_dpbDescriptor.Format };
155 };
156 
157 
158 //----------------------------------------------------------------------------------------------------------------------------------
159 template <typename T, size_t size>
160 void
update_entries(T (& picEntries)[size],std::vector<D3D12_RESOURCE_BARRIER> & outNeededTransitions)161 d3d12_video_decoder_references_manager::update_entries(T (&picEntries)[size],
162                                                        std::vector<D3D12_RESOURCE_BARRIER> &outNeededTransitions)
163 {
164    outNeededTransitions.clear();
165 
166    for (auto &picEntry : picEntries) {
167       // uint16_t update_entry(
168       //     uint16_t index, // in
169       //     ID3D12Resource*& pOutputReference, // out -> new reference slot assigned or nullptr
170       //     uint32_t& OutputSubresource, // out -> new reference slot assigned or 0
171       //     bool& outNeedsTransitionToDecodeRead // out -> indicates if output resource argument has to be transitioned
172       //     to D3D12_RESOURCE_STATE_VIDEO_DECODE_READ by the caller
173       // );
174 
175       ID3D12Resource *pOutputReference               = {};
176       uint32_t        OutputSubresource              = 0u;
177       bool            outNeedsTransitionToDecodeRead = false;
178 
179       picEntry.Index7Bits =
180          update_entry(picEntry.Index7Bits, pOutputReference, OutputSubresource, outNeedsTransitionToDecodeRead);
181 
182       if (outNeedsTransitionToDecodeRead) {
183          ///
184          /// The subresource indexing in D3D12 Video within the DPB doesn't take into account the Y, UV planes (ie.
185          /// subresource 0, 1, 2, 3..., N are different full NV12 references in the DPB) but when using the subresources
186          /// in other areas of D3D12 we need to convert it to the D3D12CalcSubresource format, explained in
187          /// https://docs.microsoft.com/en-us/windows/win32/direct3d12/subresources
188          ///
189          CD3DX12_RESOURCE_DESC refDesc(GetDesc(pOutputReference));
190          uint32_t              MipLevel, PlaneSlice, ArraySlice;
191          D3D12DecomposeSubresource(OutputSubresource,
192                                    refDesc.MipLevels,
193                                    refDesc.ArraySize(),
194                                    MipLevel,
195                                    ArraySlice,
196                                    PlaneSlice);
197 
198          for (PlaneSlice = 0; PlaneSlice < m_formatInfo.PlaneCount; PlaneSlice++) {
199             uint planeOutputSubresource = refDesc.CalcSubresource(MipLevel, ArraySlice, PlaneSlice);
200             outNeededTransitions.push_back(CD3DX12_RESOURCE_BARRIER::Transition(pOutputReference,
201                                                                                 D3D12_RESOURCE_STATE_COMMON,
202                                                                                 D3D12_RESOURCE_STATE_VIDEO_DECODE_READ,
203                                                                                 planeOutputSubresource));
204          }
205       }
206    }
207 }
208 
209 //----------------------------------------------------------------------------------------------------------------------------------
210 template <typename T, size_t size>
211 void
mark_references_in_use(const T (& picEntries)[size])212 d3d12_video_decoder_references_manager::mark_references_in_use(const T (&picEntries)[size])
213 {
214    for (auto &picEntry : picEntries) {
215       mark_reference_in_use(picEntry.Index7Bits);
216    }
217 }
218 
219 //----------------------------------------------------------------------------------------------------------------------------------
220 template <typename T, size_t size>
221 void
update_entries_av1(T (& picEntries)[size],std::vector<D3D12_RESOURCE_BARRIER> & outNeededTransitions)222 d3d12_video_decoder_references_manager::update_entries_av1(T (&picEntries)[size],
223                                                        std::vector<D3D12_RESOURCE_BARRIER> &outNeededTransitions)
224 {
225    outNeededTransitions.clear();
226 
227    for (auto &picEntry : picEntries) {
228       // uint16_t update_entry(
229       //     uint16_t index, // in
230       //     ID3D12Resource*& pOutputReference, // out -> new reference slot assigned or nullptr
231       //     uint32_t& OutputSubresource, // out -> new reference slot assigned or 0
232       //     bool& outNeedsTransitionToDecodeRead // out -> indicates if output resource argument has to be transitioned
233       //     to D3D12_RESOURCE_STATE_VIDEO_DECODE_READ by the caller
234       // );
235 
236       ID3D12Resource *pOutputReference               = {};
237       uint32_t        OutputSubresource              = 0u;
238       bool            outNeedsTransitionToDecodeRead = false;
239 
240       picEntry =
241          update_entry(picEntry, pOutputReference, OutputSubresource, outNeedsTransitionToDecodeRead);
242 
243       if (outNeedsTransitionToDecodeRead) {
244          ///
245          /// The subresource indexing in D3D12 Video within the DPB doesn't take into account the Y, UV planes (ie.
246          /// subresource 0, 1, 2, 3..., N are different full NV12 references in the DPB) but when using the subresources
247          /// in other areas of D3D12 we need to convert it to the D3D12CalcSubresource format, explained in
248          /// https://docs.microsoft.com/en-us/windows/win32/direct3d12/subresources
249          ///
250          CD3DX12_RESOURCE_DESC refDesc(GetDesc(pOutputReference));
251          uint32_t              MipLevel, PlaneSlice, ArraySlice;
252          D3D12DecomposeSubresource(OutputSubresource,
253                                    refDesc.MipLevels,
254                                    refDesc.ArraySize(),
255                                    MipLevel,
256                                    ArraySlice,
257                                    PlaneSlice);
258 
259          for (PlaneSlice = 0; PlaneSlice < m_formatInfo.PlaneCount; PlaneSlice++) {
260             uint planeOutputSubresource = refDesc.CalcSubresource(MipLevel, ArraySlice, PlaneSlice);
261             outNeededTransitions.push_back(CD3DX12_RESOURCE_BARRIER::Transition(pOutputReference,
262                                                                                 D3D12_RESOURCE_STATE_COMMON,
263                                                                                 D3D12_RESOURCE_STATE_VIDEO_DECODE_READ,
264                                                                                 planeOutputSubresource));
265          }
266       }
267    }
268 }
269 
270 //----------------------------------------------------------------------------------------------------------------------------------
271 template <typename T, size_t size>
272 void
mark_references_in_use_av1(const T (& picEntries)[size])273 d3d12_video_decoder_references_manager::mark_references_in_use_av1(const T (&picEntries)[size])
274 {
275    for (auto &picEntry : picEntries) {
276       mark_reference_in_use(picEntry);
277    }
278 }
279 
280 #endif
281