/* * Copyright © Microsoft Corporation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */ #ifndef D3D12_VIDEO_DEC_REFMGR_H #define D3D12_VIDEO_DEC_REFMGR_H #include "d3d12_video_types.h" #include "d3d12_video_dpb_storage_manager.h" #include "d3d12_util.h" #include #include struct d3d12_video_decoder_references_manager { d3d12_video_decoder_references_manager(const struct d3d12_screen * pD3D12Screen, uint32_t NodeMask, d3d12_video_decode_profile_type DecodeProfileType, d3d12_video_decode_dpb_descriptor dpbDescriptor); bool is_reference_only() { return m_dpbDescriptor.fReferenceOnly; } bool is_array_of_textures() { return m_dpbDescriptor.fArrayOfTexture; } bool is_pipe_buffer_underlying_output_decode_allocation() { return (!is_reference_only() && is_array_of_textures()); } void mark_all_references_as_unused(); void release_unused_references_texture_memory(); template void mark_references_in_use(const T (&picEntries)[size]); void mark_reference_in_use(uint16_t index); uint16_t store_future_reference(uint16_t index, _In_ ComPtr &decoderHeap, ID3D12Resource * pTexture2D, uint32_t subresourceIndex); // Will clear() argument outNeededTransitions and fill it with the necessary transitions to perform by the caller // after the method returns template void update_entries(T (&picEntries)[size], std::vector &outNeededTransitions); void get_reference_only_output( struct pipe_video_buffer * pCurrentDecodeTarget, ID3D12Resource **ppOutputReference, // out -> new reference slot assigned or nullptr uint32_t * pOutputSubresource, // out -> new reference slot assigned or nullptr bool &outNeedsTransitionToDecodeWrite // out -> indicates if output resource argument has to be transitioned to // D3D12_RESOURCE_STATE_VIDEO_DECODE_WRITE by the caller ); // Gets the output texture for the current frame to be decoded void get_current_frame_decode_output_texture(struct pipe_video_buffer *pCurrentDecodeTarget, ID3D12Resource **ppOutTexture2D, uint32_t *pOutSubresourceIndex); D3D12_VIDEO_DECODE_REFERENCE_FRAMES get_current_reference_frames(); void print_dpb(); /// /// Get the Index7Bits associated with this decode target /// If there isn't one assigned yet, gives out a fresh/unused Index7Bits /// uint8_t get_index7bits(struct pipe_video_buffer * pDecodeTarget) { bool bDecodeTargetAlreadyHasIndex = (m_DecodeTargetToOriginalIndex7Bits.count(pDecodeTarget) > 0); if(bDecodeTargetAlreadyHasIndex) { return m_DecodeTargetToOriginalIndex7Bits[pDecodeTarget]; } else { uint8_t freshIdx = m_CurrentIndex7BitsAvailable; // Make sure next "available" index is not already used. Should be cleaned up and there shouldn't be never 127 in flight used indices #if DEBUG auto it = std::find_if(m_DecodeTargetToOriginalIndex7Bits.begin(), m_DecodeTargetToOriginalIndex7Bits.end(), [&freshIdx](const std::pair< struct pipe_video_buffer*, uint8_t > &p) { return p.second == freshIdx; }); assert(it == m_DecodeTargetToOriginalIndex7Bits.end()); #endif // Point to next circular index for next call m_CurrentIndex7BitsAvailable = ((m_CurrentIndex7BitsAvailable + 1) % 127); // Assign freshIdx to pDecodeTarget m_DecodeTargetToOriginalIndex7Bits[pDecodeTarget] = freshIdx; return freshIdx; } } private: uint16_t update_entry( uint16_t index, // in ID3D12Resource *&pOutputReference, // out -> new reference slot assigned or nullptr uint32_t & OutputSubresource, // out -> new reference slot assigned or 0 bool &outNeedsTransitionToDecodeRead // out -> indicates if output resource argument has to be transitioned to // D3D12_RESOURCE_STATE_VIDEO_DECODE_READ by the caller ); uint16_t find_remapped_index(uint16_t originalIndex); struct ReferenceData { uint16_t originalIndex; bool fUsed; }; // Holds the DPB textures std::unique_ptr m_upD3D12TexturesStorageManager; std::vector m_ppHeaps; // Auxiliary allocation to QueryInterface the IUnknown's // m_upD3D12TexturesStorageManager->get_current_reference_frames().ppHeaps // containing the generic video encode/decode heap; // Holds the mapping between DXVA PicParams indices and the D3D12 indices std::vector m_referenceDXVAIndices; std::map m_DecodeTargetToOriginalIndex7Bits = { }; uint8_t m_CurrentIndex7BitsAvailable = 0; ComPtr m_pClearDecodedOutputTexture; const struct d3d12_screen * m_pD3D12Screen; uint16_t m_invalidIndex; d3d12_video_decode_dpb_descriptor m_dpbDescriptor = {}; uint16_t m_currentOutputIndex = 0; uint16_t m_currentSubresourceIndex = 0; ID3D12Resource* m_currentResource = nullptr; D3D12_FEATURE_DATA_FORMAT_INFO m_formatInfo = { m_dpbDescriptor.Format }; }; //---------------------------------------------------------------------------------------------------------------------------------- template void d3d12_video_decoder_references_manager::update_entries(T (&picEntries)[size], std::vector &outNeededTransitions) { outNeededTransitions.clear(); for (auto &picEntry : picEntries) { // uint16_t update_entry( // uint16_t index, // in // ID3D12Resource*& pOutputReference, // out -> new reference slot assigned or nullptr // uint32_t& OutputSubresource, // out -> new reference slot assigned or 0 // bool& outNeedsTransitionToDecodeRead // out -> indicates if output resource argument has to be transitioned // to D3D12_RESOURCE_STATE_VIDEO_DECODE_READ by the caller // ); ID3D12Resource *pOutputReference = {}; uint32_t OutputSubresource = 0u; bool outNeedsTransitionToDecodeRead = false; picEntry.Index7Bits = update_entry(picEntry.Index7Bits, pOutputReference, OutputSubresource, outNeedsTransitionToDecodeRead); if (outNeedsTransitionToDecodeRead) { /// /// The subresource indexing in D3D12 Video within the DPB doesn't take into account the Y, UV planes (ie. /// subresource 0, 1, 2, 3..., N are different full NV12 references in the DPB) but when using the subresources /// in other areas of D3D12 we need to convert it to the D3D12CalcSubresource format, explained in /// https://docs.microsoft.com/en-us/windows/win32/direct3d12/subresources /// CD3DX12_RESOURCE_DESC refDesc(GetDesc(pOutputReference)); uint32_t MipLevel, PlaneSlice, ArraySlice; D3D12DecomposeSubresource(OutputSubresource, refDesc.MipLevels, refDesc.ArraySize(), MipLevel, ArraySlice, PlaneSlice); for (PlaneSlice = 0; PlaneSlice < m_formatInfo.PlaneCount; PlaneSlice++) { uint planeOutputSubresource = refDesc.CalcSubresource(MipLevel, ArraySlice, PlaneSlice); outNeededTransitions.push_back(CD3DX12_RESOURCE_BARRIER::Transition(pOutputReference, D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_VIDEO_DECODE_READ, planeOutputSubresource)); } } } } //---------------------------------------------------------------------------------------------------------------------------------- template void d3d12_video_decoder_references_manager::mark_references_in_use(const T (&picEntries)[size]) { for (auto &picEntry : picEntries) { mark_reference_in_use(picEntry.Index7Bits); } } #endif