diff --git a/src/gallium/frontends/mediafoundation/context.h b/src/gallium/frontends/mediafoundation/context.h index 8b04442dd6a..3dc3cfd12f2 100644 --- a/src/gallium/frontends/mediafoundation/context.h +++ b/src/gallium/frontends/mediafoundation/context.h @@ -45,8 +45,6 @@ typedef class DX12EncodeContext pipe_resource *pPipeResourceSATDMapStats = nullptr; pipe_resource *pPipeResourceRCBitAllocMapStats = nullptr; pipe_resource *pPipeResourcePSNRStats = nullptr; - BOOL bUseSATDMapAllocator = FALSE; - BOOL bUseBitsusedMapAllocator = FALSE; // Keep all the media and sync objects until encode is done // and then signal EnqueueResourceRelease so the media @@ -206,29 +204,6 @@ typedef class DX12EncodeContext if( ( ( slice_idx == 0 ) || pOutputBitRes[slice_idx] != pOutputBitRes[slice_idx - 1] ) && pOutputBitRes[slice_idx] ) pVlScreen->pscreen->resource_destroy( pVlScreen->pscreen, pOutputBitRes[slice_idx] ); - if( pPipeResourceQPMapStats ) - pVlScreen->pscreen->resource_destroy( pVlScreen->pscreen, pPipeResourceQPMapStats ); - - if( bUseSATDMapAllocator ) - { - pPipeResourceSATDMapStats = nullptr; - } - else - { - if( pPipeResourceSATDMapStats ) - pVlScreen->pscreen->resource_destroy( pVlScreen->pscreen, pPipeResourceSATDMapStats ); - } - - if( bUseBitsusedMapAllocator ) - { - pPipeResourceRCBitAllocMapStats = nullptr; - } - else - { - if( pPipeResourceRCBitAllocMapStats ) - pVlScreen->pscreen->resource_destroy( pVlScreen->pscreen, pPipeResourceRCBitAllocMapStats ); - } - if( pPipeVideoBuffer ) pPipeVideoBuffer->destroy( pPipeVideoBuffer ); if( pDownscaledTwoPassPipeVideoBuffer ) diff --git a/src/gallium/frontends/mediafoundation/encode.cpp b/src/gallium/frontends/mediafoundation/encode.cpp index 467b56be2ba..155b4879f39 100644 --- a/src/gallium/frontends/mediafoundation/encode.cpp +++ b/src/gallium/frontends/mediafoundation/encode.cpp @@ -373,61 +373,75 @@ CDX12EncHMFT::PrepareForEncode( IMFSample *pSample, LPDX12EncodeContext *ppDX12E templ.depth0 = 1; templ.array_size = 1; - if( m_EncoderCapabilities.m_HWSupportStatsQPMapOutput.bits.supported && m_uiVideoOutputQPMapBlockSize > 0 ) - { - uint32_t block_size = ( 1 << m_EncoderCapabilities.m_HWSupportStatsQPMapOutput.bits.log2_values_block_size ); - templ.format = (enum pipe_format) m_EncoderCapabilities.m_HWSupportStatsQPMapOutput.bits.pipe_pixel_format; - templ.width0 = static_cast( std::ceil( m_uiOutputWidth / static_cast( block_size ) ) ); - templ.height0 = static_cast( std::ceil( m_uiOutputHeight / static_cast( block_size ) ) ); - CHECKNULL_GOTO( - pDX12EncodeContext->pPipeResourceQPMapStats = m_pVlScreen->pscreen->resource_create( m_pVlScreen->pscreen, &templ ), - E_OUTOFMEMORY, - done ); - } - if( m_EncoderCapabilities.m_HWSupportStatsSATDMapOutput.bits.supported && m_uiVideoSatdMapBlockSize > 0 ) { - uint32_t block_size = ( 1 << m_EncoderCapabilities.m_HWSupportStatsSATDMapOutput.bits.log2_values_block_size ); - templ.format = (enum pipe_format) m_EncoderCapabilities.m_HWSupportStatsSATDMapOutput.bits.pipe_pixel_format; - templ.width0 = static_cast( std::ceil( m_uiOutputWidth / static_cast( block_size ) ) ); - templ.height0 = static_cast( std::ceil( m_uiOutputHeight / static_cast( block_size ) ) ); - pDX12EncodeContext->bUseSATDMapAllocator = m_bUseSATDMapAllocator; - if( m_bUseSATDMapAllocator ) + if( !m_spSatdStatsBufferPool ) { - pDX12EncodeContext->pPipeResourceSATDMapStats = - AllocatePipeResourceFromAllocator( m_spSATDMapAllocator.Get(), m_pVlScreen->pscreen, &templ ); - CHECKNULL_GOTO( pDX12EncodeContext->pPipeResourceSATDMapStats, E_OUTOFMEMORY, done ); - } - else - { - CHECKNULL_GOTO( pDX12EncodeContext->pPipeResourceSATDMapStats = - m_pVlScreen->pscreen->resource_create( m_pVlScreen->pscreen, &templ ), - E_OUTOFMEMORY, - done ); + uint32_t block_size = ( 1 << m_EncoderCapabilities.m_HWSupportStatsSATDMapOutput.bits.log2_values_block_size ); + pipe_format format = (enum pipe_format) m_EncoderCapabilities.m_HWSupportStatsSATDMapOutput.bits.pipe_pixel_format; + uint32_t width0 = static_cast( std::ceil( m_uiOutputWidth / static_cast( block_size ) ) ); + uint16_t height0 = static_cast( std::ceil( m_uiOutputHeight / static_cast( block_size ) ) ); + + CHECKHR_GOTO( stats_buffer_manager::Create( m_pVlScreen, + m_pPipeContext, + MFSampleExtension_VideoEncodeSatdMap, + width0, + height0, + format, + ( m_bLowLatency ? 1 : MFT_INPUT_QUEUE_DEPTH ), + m_spSatdStatsBufferPool.GetAddressOf() ), + done ); } + pDX12EncodeContext->pPipeResourceSATDMapStats = m_spSatdStatsBufferPool->get_new_tracked_buffer(); + CHECKNULL_GOTO( pDX12EncodeContext->pPipeResourceSATDMapStats, E_OUTOFMEMORY, done ); } if( m_EncoderCapabilities.m_HWSupportStatsRCBitAllocationMapOutput.bits.supported && m_uiVideoOutputBitsUsedMapBlockSize > 0 ) { - uint32_t block_size = ( 1 << m_EncoderCapabilities.m_HWSupportStatsRCBitAllocationMapOutput.bits.log2_values_block_size ); - templ.format = (enum pipe_format) m_EncoderCapabilities.m_HWSupportStatsRCBitAllocationMapOutput.bits.pipe_pixel_format; - templ.width0 = static_cast( std::ceil( m_uiOutputWidth / static_cast( block_size ) ) ); - templ.height0 = static_cast( std::ceil( m_uiOutputHeight / static_cast( block_size ) ) ); + if( !m_spBitsUsedStatsBufferPool ) + { + uint32_t block_size = + ( 1 << m_EncoderCapabilities.m_HWSupportStatsRCBitAllocationMapOutput.bits.log2_values_block_size ); + pipe_format format = + (enum pipe_format) m_EncoderCapabilities.m_HWSupportStatsRCBitAllocationMapOutput.bits.pipe_pixel_format; + uint32_t width0 = static_cast( std::ceil( m_uiOutputWidth / static_cast( block_size ) ) ); + uint16_t height0 = static_cast( std::ceil( m_uiOutputHeight / static_cast( block_size ) ) ); - pDX12EncodeContext->bUseBitsusedMapAllocator = m_bUseBitsusedMapAllocator; - if( m_bUseBitsusedMapAllocator ) - { - pDX12EncodeContext->pPipeResourceRCBitAllocMapStats = - AllocatePipeResourceFromAllocator( m_spBitsusedMapAllocator.Get(), m_pVlScreen->pscreen, &templ ); - CHECKNULL_GOTO( pDX12EncodeContext->pPipeResourceRCBitAllocMapStats, E_OUTOFMEMORY, done ); + CHECKHR_GOTO( stats_buffer_manager::Create( m_pVlScreen, + m_pPipeContext, + MFSampleExtension_VideoEncodeBitsUsedMap, + width0, + height0, + format, + ( m_bLowLatency ? 1 : MFT_INPUT_QUEUE_DEPTH ), + m_spBitsUsedStatsBufferPool.GetAddressOf() ), + done ); } - else + pDX12EncodeContext->pPipeResourceRCBitAllocMapStats = m_spBitsUsedStatsBufferPool->get_new_tracked_buffer(); + CHECKNULL_GOTO( pDX12EncodeContext->pPipeResourceRCBitAllocMapStats, E_OUTOFMEMORY, done ); + } + + if( m_EncoderCapabilities.m_HWSupportStatsQPMapOutput.bits.supported && m_uiVideoOutputQPMapBlockSize > 0 ) + { + if( !m_spQPMapStatsBufferPool ) { - CHECKNULL_GOTO( pDX12EncodeContext->pPipeResourceRCBitAllocMapStats = - m_pVlScreen->pscreen->resource_create( m_pVlScreen->pscreen, &templ ), - E_OUTOFMEMORY, - done ); + uint32_t block_size = ( 1 << m_EncoderCapabilities.m_HWSupportStatsQPMapOutput.bits.log2_values_block_size ); + pipe_format format = (enum pipe_format) m_EncoderCapabilities.m_HWSupportStatsQPMapOutput.bits.pipe_pixel_format; + uint32_t width0 = static_cast( std::ceil( m_uiOutputWidth / static_cast( block_size ) ) ); + uint16_t height0 = static_cast( std::ceil( m_uiOutputHeight / static_cast( block_size ) ) ); + + CHECKHR_GOTO( stats_buffer_manager::Create( m_pVlScreen, + m_pPipeContext, + MFSampleExtension_VideoEncodeQPMap, + width0, + height0, + format, + ( m_bLowLatency ? 1 : MFT_INPUT_QUEUE_DEPTH ), + m_spQPMapStatsBufferPool.GetAddressOf() ), + done ); } + pDX12EncodeContext->pPipeResourceQPMapStats = m_spQPMapStatsBufferPool->get_new_tracked_buffer(); + CHECKNULL_GOTO( pDX12EncodeContext->pPipeResourceQPMapStats, E_OUTOFMEMORY, done ); } if( m_EncoderCapabilities.m_PSNRStatsSupport.bits.supports_y_channel && m_bVideoEnableFramePsnrYuv ) diff --git a/src/gallium/frontends/mediafoundation/meson.build b/src/gallium/frontends/mediafoundation/meson.build index 4deefccb020..60b8b956052 100644 --- a/src/gallium/frontends/mediafoundation/meson.build +++ b/src/gallium/frontends/mediafoundation/meson.build @@ -66,6 +66,7 @@ mediafoundation_files = files( 'reference_frames_tracker_av1.cpp', 'reference_frames_tracker_h264.cpp', 'reference_frames_tracker_hevc.cpp', + 'stats_buffer_manager.cpp', 'videobufferlock.cpp', 'wpptrace.cpp', ) diff --git a/src/gallium/frontends/mediafoundation/mfd3dmanager.cpp b/src/gallium/frontends/mediafoundation/mfd3dmanager.cpp index 6eff6b1ab76..a06312f757e 100644 --- a/src/gallium/frontends/mediafoundation/mfd3dmanager.cpp +++ b/src/gallium/frontends/mediafoundation/mfd3dmanager.cpp @@ -72,16 +72,19 @@ CMFD3DManager::Shutdown( bool bReleaseDeviceManager ) m_spVideoSampleAllocator = nullptr; } - if( m_spSATDMapAllocator ) + if( m_spSatdStatsBufferPool ) { - m_spSATDMapAllocator->UninitializeSampleAllocator(); - m_spSATDMapAllocator = nullptr; + m_spSatdStatsBufferPool.Reset(); } - if( m_spBitsusedMapAllocator ) + if( m_spBitsUsedStatsBufferPool ) { - m_spBitsusedMapAllocator->UninitializeSampleAllocator(); - m_spBitsusedMapAllocator = nullptr; + m_spBitsUsedStatsBufferPool.Reset(); + } + + if( m_spQPMapStatsBufferPool ) + { + m_spQPMapStatsBufferPool.Reset(); } if( m_spDeviceManager != nullptr ) @@ -368,9 +371,6 @@ CMFD3DManager::xOnSetD3DManager( ULONG_PTR ulParam ) CHECKNULL_GOTO( m_ContextPriorityMgr.base.get_queue_priority, MF_E_DXGI_DEVICE_NOT_INITIALIZED, done ); } - CHECKHR_GOTO( MFCreateVideoSampleAllocatorEx( IID_PPV_ARGS( &m_spSATDMapAllocator ) ), done ); - CHECKHR_GOTO( MFCreateVideoSampleAllocatorEx( IID_PPV_ARGS( &m_spBitsusedMapAllocator ) ), done ); - CHECKHR_GOTO( GetDeviceInfo(), done ); UpdateGPUFeatureFlags(); diff --git a/src/gallium/frontends/mediafoundation/mfd3dmanager.h b/src/gallium/frontends/mediafoundation/mfd3dmanager.h index 58dc2abeee4..fc26e119e14 100644 --- a/src/gallium/frontends/mediafoundation/mfd3dmanager.h +++ b/src/gallium/frontends/mediafoundation/mfd3dmanager.h @@ -48,6 +48,8 @@ #include "macros.h" +#include "stats_buffer_manager.h" + // Use the Windows SDK dxcore include (e.g directx/dxcore uses DirectX-Headers) #include @@ -98,10 +100,11 @@ class CMFD3DManager ComPtr m_spVideoDevice; ComPtr m_spStagingQueue; ComPtr m_spVideoSampleAllocator; // Used for software input samples that need to be copied - ComPtr m_spSATDMapAllocator; - ComPtr m_spBitsusedMapAllocator; - BOOL m_bUseSATDMapAllocator = FALSE; - BOOL m_bUseBitsusedMapAllocator = FALSE; + + ComPtr m_spSatdStatsBufferPool; + ComPtr m_spBitsUsedStatsBufferPool; + ComPtr m_spQPMapStatsBufferPool; + UINT32 m_uiResetToken = 0; HANDLE m_hDevice = NULL; struct vl_screen *m_pVlScreen = nullptr; diff --git a/src/gallium/frontends/mediafoundation/mftransform.cpp b/src/gallium/frontends/mediafoundation/mftransform.cpp index 95e564f113a..16a041562a3 100644 --- a/src/gallium/frontends/mediafoundation/mftransform.cpp +++ b/src/gallium/frontends/mediafoundation/mftransform.cpp @@ -565,15 +565,9 @@ CDX12EncHMFT::OnOutputTypeChanged() if( bResolutionChange ) { - ConfigureMapSampleAllocatorHelper( m_spSATDMapAllocator, - m_EncoderCapabilities.m_HWSupportStatsSATDMapOutput, - m_uiVideoSatdMapBlockSize, - m_bUseSATDMapAllocator ); - - ConfigureMapSampleAllocatorHelper( m_spBitsusedMapAllocator, - m_EncoderCapabilities.m_HWSupportStatsRCBitAllocationMapOutput, - m_uiVideoOutputBitsUsedMapBlockSize, - m_bUseBitsusedMapAllocator ); + m_spSatdStatsBufferPool.Reset(); + m_spBitsUsedStatsBufferPool.Reset(); + m_spQPMapStatsBufferPool.Reset(); } // Indicate that we'll be adding MF_NALU_LENGTH_INFORMATION on each output sample that comes @@ -1469,48 +1463,48 @@ CDX12EncHMFT::xThreadProc( void *pCtx ) } } - // Conditionally attach output QP map - if( pThis->m_uiVideoOutputQPMapBlockSize && pDX12EncodeContext->pPipeResourceQPMapStats != nullptr ) + // Conditionally attach output QP map (d3d12resource), tracking will be added to the d3d12resource and when the app + // releases the MF sample, the d3d12resource will be returned back to the pool + if( pThis->m_uiVideoOutputQPMapBlockSize && pDX12EncodeContext->pPipeResourceQPMapStats != nullptr && + pThis->m_spQPMapStatsBufferPool ) { - HRESULT hr = MFAttachPipeResourceAsSampleExtension( pThis->m_pPipeContext, - pDX12EncodeContext->pPipeResourceQPMapStats, - pDX12EncodeContext->pSyncObjectQueue, - MFSampleExtension_VideoEncodeQPMap, - spOutputSample.Get() ); - + HRESULT hr = pThis->m_spQPMapStatsBufferPool->AttachPipeResourceAsSampleExtension( + pDX12EncodeContext->pPipeResourceQPMapStats, + pDX12EncodeContext->pSyncObjectQueue, + spOutputSample.Get() ); if( FAILED( hr ) ) { - MFE_INFO( "[dx12 hmft 0x%p] QPMap: MFAttachPipeResourceAsSampleExtension failed - hr=0x%08x", pThis, hr ); + MFE_INFO( "[dx12 hmft 0x%p] QPMap: AttachPipeResourceAsSampleExtension failed - hr=0x%08x", pThis, hr ); } } - // Conditionally attach output bits used map - if( pThis->m_uiVideoOutputBitsUsedMapBlockSize && pDX12EncodeContext->pPipeResourceRCBitAllocMapStats != nullptr ) + // Conditionally attach output bits used map (d3d12resource), tracking will be added to the d3d12resource and when + // the app releases the MF sample, the d3d12resource will be returned back to the pool + if( pThis->m_uiVideoOutputBitsUsedMapBlockSize && pDX12EncodeContext->pPipeResourceRCBitAllocMapStats != nullptr && + pThis->m_spBitsUsedStatsBufferPool ) { - HRESULT hr = MFAttachPipeResourceAsSampleExtension( pThis->m_pPipeContext, - pDX12EncodeContext->pPipeResourceRCBitAllocMapStats, - pDX12EncodeContext->pSyncObjectQueue, - MFSampleExtension_VideoEncodeBitsUsedMap, - spOutputSample.Get() ); - + HRESULT hr = pThis->m_spBitsUsedStatsBufferPool->AttachPipeResourceAsSampleExtension( + pDX12EncodeContext->pPipeResourceRCBitAllocMapStats, + pDX12EncodeContext->pSyncObjectQueue, + spOutputSample.Get() ); if( FAILED( hr ) ) { - MFE_INFO( "[dx12 hmft 0x%p] BitsUsed: MFAttachPipeResourceAsSampleExtension failed - hr=0x%08x", pThis, hr ); + MFE_INFO( "[dx12 hmft 0x%p] BitsUsed: AttachPipeResourceAsSampleExtension failed - hr=0x%08x", pThis, hr ); } } - // Conditionally attach SATD map - if( pThis->m_uiVideoSatdMapBlockSize && pDX12EncodeContext->pPipeResourceSATDMapStats != nullptr ) + // Conditionally attach SATD map (d3d12resource), tracking will be added to the d3d12resource and when the app + // releases the MF sample, the d3d12resource will be returned back to the pool + if( pThis->m_uiVideoSatdMapBlockSize && pDX12EncodeContext->pPipeResourceSATDMapStats != nullptr && + pThis->m_spSatdStatsBufferPool ) { - HRESULT hr = MFAttachPipeResourceAsSampleExtension( pThis->m_pPipeContext, - pDX12EncodeContext->pPipeResourceSATDMapStats, - pDX12EncodeContext->pSyncObjectQueue, - MFSampleExtension_VideoEncodeSatdMap, - spOutputSample.Get() ); - + HRESULT hr = pThis->m_spSatdStatsBufferPool->AttachPipeResourceAsSampleExtension( + pDX12EncodeContext->pPipeResourceSATDMapStats, + pDX12EncodeContext->pSyncObjectQueue, + spOutputSample.Get() ); if( FAILED( hr ) ) { - MFE_INFO( "[dx12 hmft 0x%p] SATDMap: MFAttachPipeResourceAsSampleExtension failed - hr=0x%08x", pThis, hr ); + MFE_INFO( "[dx12 hmft 0x%p] SATDMap: AttachPipeResourceAsSampleExtension failed - hr=0x%08x", pThis, hr ); } } @@ -2085,16 +2079,6 @@ CDX12EncHMFT::ProcessMessage( MFT_MESSAGE_TYPE eMessage, ULONG_PTR ulParam ) { m_EncoderCapabilities.initialize( m_pPipeContext->screen, m_outputPipeProfile ); } - - ConfigureMapSampleAllocatorHelper( m_spSATDMapAllocator, - m_EncoderCapabilities.m_HWSupportStatsSATDMapOutput, - m_uiVideoSatdMapBlockSize, - m_bUseSATDMapAllocator ); - - ConfigureMapSampleAllocatorHelper( m_spBitsusedMapAllocator, - m_EncoderCapabilities.m_HWSupportStatsRCBitAllocationMapOutput, - m_uiVideoOutputBitsUsedMapBlockSize, - m_bUseBitsusedMapAllocator ); break; } } diff --git a/src/gallium/frontends/mediafoundation/staticasynccallback.h b/src/gallium/frontends/mediafoundation/staticasynccallback.h new file mode 100644 index 00000000000..0cdbdeb3d6e --- /dev/null +++ b/src/gallium/frontends/mediafoundation/staticasynccallback.h @@ -0,0 +1,107 @@ +#ifndef __STATICASYNCCALLBACK__ +#define __STATICASYNCCALLBACK__ + +//////////////////////////////////////////////////////// +// +#define STATICASYNCCALLBACK( Callback, Parent ) \ + class Callback##AsyncCallback; \ + friend class Callback##AsyncCallback; \ + class Callback##AsyncCallback : public IMFAsyncCallback \ + { \ + public: \ + STDMETHOD_( ULONG, AddRef )() \ + { \ + Parent *pThis = ( (Parent *) ( (BYTE *) this - offsetof( Parent, m_x##Callback ) ) ); \ + return pThis->AddRef(); \ + } \ + STDMETHOD_( ULONG, Release )() \ + { \ + Parent *pThis = ( (Parent *) ( (BYTE *) this - offsetof( Parent, m_x##Callback ) ) ); \ + return pThis->Release(); \ + } \ + STDMETHOD( QueryInterface )( REFIID riid, __RPC__deref_out _Result_nullonfailure_ void **ppvObject ) \ + { \ + return E_NOINTERFACE; \ + } \ + STDMETHOD( GetParameters )( __RPC__out DWORD * pdwFlags, __RPC__out DWORD *pdwQueue ) \ + { \ + return S_OK; \ + } \ + STDMETHOD( Invoke )( __RPC__in_opt IMFAsyncResult * pResult ) \ + { \ + Callback( pResult ); \ + return S_OK; \ + } \ + } m_x##Callback; + + +//////////////////////////////////////////////////////// +// +// +// We need to support QI interface so that DCOM is happy when it tries to marshal the interface pointer +// + +#define METHODASYNCCALLBACKEX( Callback, Parent, Flag, Queue ) \ + class Callback##AsyncCallback; \ + friend class Callback##AsyncCallback; \ + class Callback##AsyncCallback : public IMFAsyncCallback \ + { \ + public: \ + STDMETHOD_( ULONG, AddRef )() \ + { \ + return GetParent()->AddRef(); \ + } \ + STDMETHOD_( ULONG, Release )() \ + { \ + return GetParent()->Release(); \ + } \ + STDMETHOD( QueryInterface )( REFIID riid, __RPC__deref_out _Result_nullonfailure_ void **ppvObject ) \ + { \ + if( riid == IID_IMFAsyncCallback || riid == IID_IUnknown ) \ + { \ + ( *ppvObject ) = this; \ + AddRef(); \ + return S_OK; \ + } \ + ( *ppvObject ) = NULL; \ + return E_NOINTERFACE; \ + } \ + STDMETHOD( GetParameters )( __RPC__out DWORD * pdwFlags, __RPC__out DWORD *pdwQueue ) \ + { \ + *pdwFlags = Flag; \ + *pdwQueue = Queue; \ + return S_OK; \ + } \ + STDMETHOD( Invoke )( __RPC__in_opt IMFAsyncResult * pResult ) \ + { \ + GetParent()->Callback( pResult ); \ + return S_OK; \ + } \ + \ + protected: \ + Parent *GetParent() \ + { \ + return ( (Parent *) ( (BYTE *) this - offsetof( Parent, m_x##Callback ) ) ); \ + } \ + } m_x##Callback; + +//////////////////////////////////////////////////////// +// +#define METHODFASTCALLBACK( Callback, Parent ) \ + METHODASYNCCALLBACKEX( Callback, Parent, MFASYNC_FAST_IO_PROCESSING_CALLBACK, MFASYNC_CALLBACK_QUEUE_STANDARD ) + +#define METHODASYNCCALLBACK( Callback, Parent ) METHODASYNCCALLBACKEX( Callback, Parent, 0, MFASYNC_CALLBACK_QUEUE_STANDARD ) + +#define METHODASYNCRTCALLBACK( Callback, Parent ) METHODASYNCCALLBACKEX( Callback, Parent, 0, MFASYNC_CALLBACK_QUEUE_RT ) + +#define METHODASYNCIOCALLBACK( Callback, Parent ) \ + METHODASYNCCALLBACKEX( Callback, Parent, MFASYNC_FAST_IO_PROCESSING_CALLBACK, MFASYNC_CALLBACK_QUEUE_IO ) + +//////////////////////////////////////////////////////// +// +#define METHODASYNCCALLBACKEX2( Callback, Parent, GetQueue ) METHODASYNCCALLBACKEX( Callback, Parent, 0, GetParent()->GetQueue() ) + +#define METHODASYNCCALLBACKEX3( Callback, Parent, GetFlags, GetQueue ) \ + METHODASYNCCALLBACKEX( Callback, Parent, GetParent()->GetFlags(), GetParent()->GetQueue() ) + +#endif \ No newline at end of file diff --git a/src/gallium/frontends/mediafoundation/stats_buffer_manager.cpp b/src/gallium/frontends/mediafoundation/stats_buffer_manager.cpp new file mode 100644 index 00000000000..d6eb0b96ee7 --- /dev/null +++ b/src/gallium/frontends/mediafoundation/stats_buffer_manager.cpp @@ -0,0 +1,311 @@ +/* + * 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. + */ + +#include +#include +#include +#include +#include "wpptrace.h" + +#include "macros.h" +#include "stats_buffer_manager.h" +#include "stats_buffer_manager.tmh" + +using namespace Microsoft::WRL; + +HRESULT __stdcall stats_buffer_manager::QueryInterface( const IID &riid, void **ppvObject ) +{ + if( riid == IID_IUnknown ) + { + // If the requested IID is supported, return 'this' pointer + *ppvObject = static_cast( this ); + // Must call AddRef because we are returning a valid interface pointer + AddRef(); + return S_OK; + } + + // Interface not supported + *ppvObject = NULL; + return E_NOINTERFACE; +} + +ULONG __stdcall stats_buffer_manager::AddRef() +{ + return InterlockedIncrement( &m_refCount ); +} + +ULONG __stdcall stats_buffer_manager::Release() +{ + ULONG ulCount = InterlockedDecrement( &m_refCount ); + if( ulCount == 0 ) + { + delete this; + } + return ulCount; +} + +HRESULT +stats_buffer_manager::Create( struct vl_screen *pVlScreen, + struct pipe_context *pPipeContext, + REFGUID guidExtension, + uint32_t width, + uint16_t height, + enum pipe_format buffer_format, + unsigned pool_size, + stats_buffer_manager **ppInstance ) +{ + if( !ppInstance ) + return E_INVALIDARG; + + *ppInstance = nullptr; + + HRESULT hr; + auto pInstance = new ( std::nothrow ) + stats_buffer_manager( pVlScreen, pPipeContext, guidExtension, width, height, buffer_format, pool_size, hr ); + if( !pInstance ) + return E_OUTOFMEMORY; + + if( FAILED( hr ) ) + { + delete pInstance; + return hr; + } + + pInstance->m_refCount = 1; + *ppInstance = pInstance; + return S_OK; +} + +// retrieve a buffer from the pool +struct pipe_resource * +stats_buffer_manager::get_new_tracked_buffer() +{ + auto lock = std::lock_guard( m_lock ); + for( auto &entry : m_pool ) + { + if( !entry.used ) + { + entry.used = true; + return entry.buffer; + } + } + + assert( false ); // Did not find an unused buffer + return NULL; +} + +// release a buffer back to the pool +void +stats_buffer_manager::release_tracked_buffer( void *target ) +{ + auto lock = std::lock_guard( m_lock ); + for( auto &entry : m_pool ) + { + struct winsys_handle whandle = {}; + whandle.type = WINSYS_HANDLE_TYPE_D3D12_RES; + m_pVlScreen->pscreen->resource_get_handle( m_pVlScreen->pscreen, m_pPipeContext, entry.buffer, &whandle, 0u ); + if( whandle.com_obj == target ) + { + entry.used = false; + break; + } + } +} + +stats_buffer_manager::stats_buffer_manager( struct vl_screen *pVlScreen, + struct pipe_context *pPipeContext, + REFGUID resourceGUID, + uint32_t width, + uint16_t height, + enum pipe_format buffer_format, + unsigned pool_size, + HRESULT &hr ) + : m_pVlScreen( pVlScreen ), m_pPipeContext( pPipeContext ), m_resourceGUID( resourceGUID ), m_pool( pool_size, { NULL, false } ) +{ + hr = S_OK; + m_template.target = PIPE_TEXTURE_2D; + m_template.usage = PIPE_USAGE_DEFAULT; + m_template.depth0 = 1; + m_template.array_size = 1; + + m_template.width0 = width; + m_template.height0 = height; + m_template.format = buffer_format; + + for( auto &entry : m_pool ) + { + entry.buffer = m_pVlScreen->pscreen->resource_create( m_pVlScreen->pscreen, &m_template ); + if( !entry.buffer ) + { + assert( true ); + hr = E_FAIL; + break; + } + } + + if( FAILED( hr ) ) + { + for( auto &entry : m_pool ) + { + if( entry.buffer ) + { + m_pVlScreen->pscreen->resource_destroy( m_pVlScreen->pscreen, entry.buffer ); + } + } + } +} + +stats_buffer_manager::~stats_buffer_manager() +{ + for( auto &entry : m_pool ) + { + if( entry.buffer ) + { + m_pVlScreen->pscreen->resource_destroy( m_pVlScreen->pscreen, entry.buffer ); + } + } +} + +// callback from IMFTrackSample (i.e. application) +IFACEMETHODIMP +stats_buffer_manager::OnSampleAvailable( IMFAsyncResult *pResult ) +{ + HRESULT hr = S_OK; + ComPtr spUnk; + ComPtr spSample; + ComPtr spMediaBuffer; + ComPtr spDXGIBuffer; + ComPtr spOutputSync; + ComPtr spSyncObj; + ComPtr spDXGISurface; + HANDLE hFree = NULL; + + CHECKHR_GOTO( pResult->GetState( &spUnk ), done ); + CHECKHR_GOTO( spUnk.As( &spSample ), done ); + CHECKHR_GOTO( spSample->GetBufferByIndex( 0, &spMediaBuffer ), done ); + CHECKHR_GOTO( spMediaBuffer.As( &spDXGIBuffer ), done ); + CHECKHR_GOTO( spDXGIBuffer->GetResource( IID_PPV_ARGS( &spDXGISurface ) ), done ); + + CHECKHR_GOTO( spDXGIBuffer->GetUnknown( MF_D3D12_SYNCHRONIZATION_OBJECT, IID_PPV_ARGS( &spOutputSync ) ), done ); + CHECKHR_GOTO( spOutputSync.As( &spSyncObj ), done ); + hFree = CreateEvent( nullptr, FALSE, FALSE, nullptr ); + if( !hFree ) + { + CHECKHR_GOTO( HRESULT_FROM_WIN32( GetLastError() ), done ); + } + CHECKHR_GOTO( spSyncObj->SignalEventOnFinalResourceRelease( hFree ), done ); + (void) WaitForSingleObject( hFree, INFINITE ); + spOutputSync.Reset(); + + release_tracked_buffer( (void *) spDXGISurface.Get() ); + +done: + if( hFree ) + { + CloseHandle( hFree ); + } + return hr; +} + +// Converts a Gallium pipe_resource into a D3D12 resource and wraps it as an IMFMediaBuffer, +// then attaches it as a sample extension on an IMFSample using the specified GUID. +HRESULT +stats_buffer_manager::AttachPipeResourceAsSampleExtension( struct pipe_resource *pPipeRes, + ID3D12CommandQueue *pSyncObjectQueue, + IMFSample *pSample ) +{ + HRESULT hr = S_OK; + if( !pPipeRes || !pSample || !pSyncObjectQueue ) + { + return E_INVALIDARG; + } + + struct winsys_handle whandle = {}; + whandle.type = WINSYS_HANDLE_TYPE_D3D12_RES; + + if( !m_pPipeContext->screen->resource_get_handle( m_pPipeContext->screen, m_pPipeContext, pPipeRes, &whandle, 0u ) ) + { + return E_FAIL; + } + + if( !whandle.com_obj ) + { + return E_POINTER; + } + + ComPtr spTrackedSample; + hr = MFCreateTrackedSample( &spTrackedSample ); + if( FAILED( hr ) ) + { + return hr; + } + hr = spTrackedSample->SetAllocator( &m_xOnSampleAvailable, spTrackedSample.Get() ); + if( FAILED( hr ) ) + { + return hr; + } + + ComPtr spSample; + hr = spTrackedSample.As( &spSample ); + if( FAILED( hr ) ) + { + return hr; + } + + ID3D12Resource *pD3D12Res = static_cast( whandle.com_obj ); + ComPtr spMediaBuffer; + hr = MFCreateDXGISurfaceBuffer( __uuidof( ID3D12Resource ), pD3D12Res, 0, FALSE, &spMediaBuffer ); + + if( FAILED( hr ) ) + { + return hr; + } + + // Tell MF that this buffer is ready to use. + ComPtr spOutputSync; // needed to call Lock() for IMFMediaBuffer. + ComPtr spDxgiBuffer; + hr = spMediaBuffer->QueryInterface( IID_PPV_ARGS( &spDxgiBuffer ) ); + if( SUCCEEDED( hr ) ) + { + hr = spDxgiBuffer->GetUnknown( MF_D3D12_SYNCHRONIZATION_OBJECT, IID_PPV_ARGS( &spOutputSync ) ); + if( SUCCEEDED( hr ) ) + { + hr = spOutputSync->EnqueueResourceReady( pSyncObjectQueue ); + + spSample->AddBuffer( spMediaBuffer.Get() ); + + if( FAILED( hr ) ) + return hr; + } + else + { + return hr; + } + } + else + { + return hr; + } + + return pSample->SetUnknown( m_resourceGUID, spMediaBuffer.Get() ); +} diff --git a/src/gallium/frontends/mediafoundation/stats_buffer_manager.h b/src/gallium/frontends/mediafoundation/stats_buffer_manager.h new file mode 100644 index 00000000000..5bae28dd1c1 --- /dev/null +++ b/src/gallium/frontends/mediafoundation/stats_buffer_manager.h @@ -0,0 +1,98 @@ +/* + * 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. + */ + +#pragma once + +#include + +#include "gallium/include/frontend/sw_winsys.h" +#include "gallium/winsys/sw/null/null_sw_winsys.h" +#include "util/u_video.h" +#include "vl/vl_winsys.h" + +#include +#include + +#include +#include +#include +#include "pipe_headers.h" +#include "staticasynccallback.h" + + +class stats_buffer_manager : public IUnknown +{ + public: + // retrieve a new tracked buffer from the pool + struct pipe_resource *get_new_tracked_buffer(); + + // release a tracked buffer back to the pool + void release_tracked_buffer( void *target ); + + HRESULT __stdcall QueryInterface( const IID &riid, void **ppvObject ) override; + ULONG __stdcall AddRef() override; + ULONG __stdcall Release() override; + + HRESULT + AttachPipeResourceAsSampleExtension( struct pipe_resource *pPipeRes, ID3D12CommandQueue *pSyncObjectQueue, IMFSample *pSample ); + + static HRESULT Create( struct vl_screen *pVlScreen, + struct pipe_context *pPipeContext, + REFGUID guidExtension, + uint32_t width, + uint16_t height, + enum pipe_format buffer_format, + unsigned pool_size, + stats_buffer_manager **ppInstance ); + + private: + stats_buffer_manager( struct vl_screen *m_pVlScreen, + pipe_context *pPipeContext, + REFGUID guidExtension, + uint32_t width, + uint16_t height, + enum pipe_format buffer_format, + unsigned pool_size, + HRESULT &hr ); + + ~stats_buffer_manager(); + + STDMETHOD( OnSampleAvailable )( __in IMFAsyncResult *pAsyncResult ); + METHODASYNCCALLBACKEX( OnSampleAvailable, stats_buffer_manager, 0, MFASYNC_CALLBACK_QUEUE_MULTITHREADED ); + + std::mutex m_lock; + GUID m_resourceGUID {}; + ULONG m_refCount = 0; + + struct vl_screen *m_pVlScreen = nullptr; + struct pipe_context *m_pPipeContext = nullptr; + struct pipe_resource m_template = {}; + + struct stats_buffer_manager_pool_entry + { + struct pipe_resource *buffer; + bool used; + }; + + std::vector m_pool; +};