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 void mark_reference_in_use(uint16_t index); 60 61 uint16_t store_future_reference(uint16_t index, 62 _In_ ComPtr<ID3D12VideoDecoderHeap> &decoderHeap, 63 ID3D12Resource * pTexture2D, 64 uint32_t subresourceIndex); 65 66 // Will clear() argument outNeededTransitions and fill it with the necessary transitions to perform by the caller 67 // after the method returns 68 template <typename T, size_t size> 69 void update_entries(T (&picEntries)[size], std::vector<D3D12_RESOURCE_BARRIER> &outNeededTransitions); 70 71 void get_reference_only_output( 72 struct pipe_video_buffer * pCurrentDecodeTarget, 73 ID3D12Resource **ppOutputReference, // out -> new reference slot assigned or nullptr 74 uint32_t * pOutputSubresource, // out -> new reference slot assigned or nullptr 75 bool &outNeedsTransitionToDecodeWrite // out -> indicates if output resource argument has to be transitioned to 76 // D3D12_RESOURCE_STATE_VIDEO_DECODE_WRITE by the caller 77 ); 78 79 // Gets the output texture for the current frame to be decoded 80 void get_current_frame_decode_output_texture(struct pipe_video_buffer *pCurrentDecodeTarget, ID3D12Resource **ppOutTexture2D, uint32_t *pOutSubresourceIndex); 81 82 D3D12_VIDEO_DECODE_REFERENCE_FRAMES get_current_reference_frames(); 83 84 void print_dpb(); 85 86 /// 87 /// Get the Index7Bits associated with this decode target 88 /// If there isn't one assigned yet, gives out a fresh/unused Index7Bits 89 /// get_index7bitsd3d12_video_decoder_references_manager90 uint8_t get_index7bits(struct pipe_video_buffer * pDecodeTarget) { 91 bool bDecodeTargetAlreadyHasIndex = (m_DecodeTargetToOriginalIndex7Bits.count(pDecodeTarget) > 0); 92 if(bDecodeTargetAlreadyHasIndex) 93 { 94 return m_DecodeTargetToOriginalIndex7Bits[pDecodeTarget]; 95 } else { 96 uint8_t freshIdx = m_CurrentIndex7BitsAvailable; 97 98 // Make sure next "available" index is not already used. Should be cleaned up and there shouldn't be never 127 in flight used indices 99 #if DEBUG 100 auto it = std::find_if(m_DecodeTargetToOriginalIndex7Bits.begin(), m_DecodeTargetToOriginalIndex7Bits.end(), 101 [&freshIdx](const std::pair< struct pipe_video_buffer*, uint8_t > &p) { 102 return p.second == freshIdx; 103 }); 104 105 assert(it == m_DecodeTargetToOriginalIndex7Bits.end()); 106 #endif 107 108 // Point to next circular index for next call 109 m_CurrentIndex7BitsAvailable = ((m_CurrentIndex7BitsAvailable + 1) % 127); 110 111 // Assign freshIdx to pDecodeTarget 112 m_DecodeTargetToOriginalIndex7Bits[pDecodeTarget] = freshIdx; 113 return freshIdx; 114 } 115 } 116 117 private: 118 uint16_t update_entry( 119 uint16_t index, // in 120 ID3D12Resource *&pOutputReference, // out -> new reference slot assigned or nullptr 121 uint32_t & OutputSubresource, // out -> new reference slot assigned or 0 122 bool &outNeedsTransitionToDecodeRead // out -> indicates if output resource argument has to be transitioned to 123 // D3D12_RESOURCE_STATE_VIDEO_DECODE_READ by the caller 124 ); 125 126 uint16_t find_remapped_index(uint16_t originalIndex); 127 128 struct ReferenceData 129 { 130 uint16_t originalIndex; 131 bool fUsed; 132 }; 133 134 // Holds the DPB textures 135 std::unique_ptr<d3d12_video_dpb_storage_manager_interface> m_upD3D12TexturesStorageManager; 136 std::vector<ID3D12VideoDecoderHeap *> 137 m_ppHeaps; // Auxiliary allocation to QueryInterface the IUnknown's 138 // m_upD3D12TexturesStorageManager->get_current_reference_frames().ppHeaps 139 // containing the generic video encode/decode heap; 140 141 // Holds the mapping between DXVA PicParams indices and the D3D12 indices 142 std::vector<ReferenceData> m_referenceDXVAIndices; 143 144 std::map<struct pipe_video_buffer *, uint8_t> m_DecodeTargetToOriginalIndex7Bits = { }; 145 uint8_t m_CurrentIndex7BitsAvailable = 0; 146 147 ComPtr<ID3D12Resource> m_pClearDecodedOutputTexture; 148 149 const struct d3d12_screen * m_pD3D12Screen; 150 uint16_t m_invalidIndex; 151 d3d12_video_decode_dpb_descriptor m_dpbDescriptor = {}; 152 uint16_t m_currentOutputIndex = 0; 153 uint16_t m_currentSubresourceIndex = 0; 154 ID3D12Resource* m_currentResource = nullptr; 155 D3D12_FEATURE_DATA_FORMAT_INFO m_formatInfo = { m_dpbDescriptor.Format }; 156 }; 157 158 159 //---------------------------------------------------------------------------------------------------------------------------------- 160 template <typename T, size_t size> 161 void 162 d3d12_video_decoder_references_manager::update_entries(T (&picEntries)[size], 163 std::vector<D3D12_RESOURCE_BARRIER> &outNeededTransitions) 164 { 165 outNeededTransitions.clear(); 166 167 for (auto &picEntry : picEntries) { 168 // uint16_t update_entry( 169 // uint16_t index, // in 170 // ID3D12Resource*& pOutputReference, // out -> new reference slot assigned or nullptr 171 // uint32_t& OutputSubresource, // out -> new reference slot assigned or 0 172 // bool& outNeedsTransitionToDecodeRead // out -> indicates if output resource argument has to be transitioned 173 // to D3D12_RESOURCE_STATE_VIDEO_DECODE_READ by the caller 174 // ); 175 176 ID3D12Resource *pOutputReference = {}; 177 uint32_t OutputSubresource = 0u; 178 bool outNeedsTransitionToDecodeRead = false; 179 180 picEntry.Index7Bits = 181 update_entry(picEntry.Index7Bits, pOutputReference, OutputSubresource, outNeedsTransitionToDecodeRead); 182 183 if (outNeedsTransitionToDecodeRead) { 184 /// 185 /// The subresource indexing in D3D12 Video within the DPB doesn't take into account the Y, UV planes (ie. 186 /// subresource 0, 1, 2, 3..., N are different full NV12 references in the DPB) but when using the subresources 187 /// in other areas of D3D12 we need to convert it to the D3D12CalcSubresource format, explained in 188 /// https://docs.microsoft.com/en-us/windows/win32/direct3d12/subresources 189 /// 190 CD3DX12_RESOURCE_DESC refDesc(GetDesc(pOutputReference)); 191 uint32_t MipLevel, PlaneSlice, ArraySlice; 192 D3D12DecomposeSubresource(OutputSubresource, 193 refDesc.MipLevels, 194 refDesc.ArraySize(), 195 MipLevel, 196 ArraySlice, 197 PlaneSlice); 198 199 for (PlaneSlice = 0; PlaneSlice < m_formatInfo.PlaneCount; PlaneSlice++) { 200 uint planeOutputSubresource = refDesc.CalcSubresource(MipLevel, ArraySlice, PlaneSlice); 201 outNeededTransitions.push_back(CD3DX12_RESOURCE_BARRIER::Transition(pOutputReference, 202 D3D12_RESOURCE_STATE_COMMON, 203 D3D12_RESOURCE_STATE_VIDEO_DECODE_READ, 204 planeOutputSubresource)); 205 } 206 } 207 } 208 } 209 210 //---------------------------------------------------------------------------------------------------------------------------------- 211 template <typename T, size_t size> 212 void 213 d3d12_video_decoder_references_manager::mark_references_in_use(const T (&picEntries)[size]) 214 { 215 for (auto &picEntry : picEntries) { 216 mark_reference_in_use(picEntry.Index7Bits); 217 } 218 } 219 220 #endif 221