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