mediafoundation: add stats resource pool so we can use pool for QP map as well
Reviewed-by: Yubo Xie <yuboxie@microsoft.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/37982>
This commit is contained in:
@@ -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 )
|
||||
|
||||
@@ -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<uint32_t>( std::ceil( m_uiOutputWidth / static_cast<float>( block_size ) ) );
|
||||
templ.height0 = static_cast<uint16_t>( std::ceil( m_uiOutputHeight / static_cast<float>( 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<uint32_t>( std::ceil( m_uiOutputWidth / static_cast<float>( block_size ) ) );
|
||||
templ.height0 = static_cast<uint16_t>( std::ceil( m_uiOutputHeight / static_cast<float>( 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<uint32_t>( std::ceil( m_uiOutputWidth / static_cast<float>( block_size ) ) );
|
||||
uint16_t height0 = static_cast<uint16_t>( std::ceil( m_uiOutputHeight / static_cast<float>( 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<uint32_t>( std::ceil( m_uiOutputWidth / static_cast<float>( block_size ) ) );
|
||||
templ.height0 = static_cast<uint16_t>( std::ceil( m_uiOutputHeight / static_cast<float>( 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<uint32_t>( std::ceil( m_uiOutputWidth / static_cast<float>( block_size ) ) );
|
||||
uint16_t height0 = static_cast<uint16_t>( std::ceil( m_uiOutputHeight / static_cast<float>( 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<uint32_t>( std::ceil( m_uiOutputWidth / static_cast<float>( block_size ) ) );
|
||||
uint16_t height0 = static_cast<uint16_t>( std::ceil( m_uiOutputHeight / static_cast<float>( 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 )
|
||||
|
||||
@@ -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',
|
||||
)
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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 <dxcore.h>
|
||||
|
||||
@@ -98,10 +100,11 @@ class CMFD3DManager
|
||||
ComPtr<ID3D12VideoDevice> m_spVideoDevice;
|
||||
ComPtr<ID3D12CommandQueue> m_spStagingQueue;
|
||||
ComPtr<IMFVideoSampleAllocatorEx> m_spVideoSampleAllocator; // Used for software input samples that need to be copied
|
||||
ComPtr<IMFVideoSampleAllocatorEx> m_spSATDMapAllocator;
|
||||
ComPtr<IMFVideoSampleAllocatorEx> m_spBitsusedMapAllocator;
|
||||
BOOL m_bUseSATDMapAllocator = FALSE;
|
||||
BOOL m_bUseBitsusedMapAllocator = FALSE;
|
||||
|
||||
ComPtr<stats_buffer_manager> m_spSatdStatsBufferPool;
|
||||
ComPtr<stats_buffer_manager> m_spBitsUsedStatsBufferPool;
|
||||
ComPtr<stats_buffer_manager> m_spQPMapStatsBufferPool;
|
||||
|
||||
UINT32 m_uiResetToken = 0;
|
||||
HANDLE m_hDevice = NULL;
|
||||
struct vl_screen *m_pVlScreen = nullptr;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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 <mfapi.h>
|
||||
#include <mfd3d12.h>
|
||||
#include <mfidl.h>
|
||||
#include <wrl/client.h>
|
||||
#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<IUnknown *>( 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<std::mutex>( 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<std::mutex>( 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<IUnknown> spUnk;
|
||||
ComPtr<IMFSample> spSample;
|
||||
ComPtr<IMFMediaBuffer> spMediaBuffer;
|
||||
ComPtr<IMFDXGIBuffer> spDXGIBuffer;
|
||||
ComPtr<IMFD3D12SynchronizationObjectCommands> spOutputSync;
|
||||
ComPtr<IMFD3D12SynchronizationObject> spSyncObj;
|
||||
ComPtr<ID3D12Resource> 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<IMFTrackedSample> spTrackedSample;
|
||||
hr = MFCreateTrackedSample( &spTrackedSample );
|
||||
if( FAILED( hr ) )
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
hr = spTrackedSample->SetAllocator( &m_xOnSampleAvailable, spTrackedSample.Get() );
|
||||
if( FAILED( hr ) )
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
|
||||
ComPtr<IMFSample> spSample;
|
||||
hr = spTrackedSample.As( &spSample );
|
||||
if( FAILED( hr ) )
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
|
||||
ID3D12Resource *pD3D12Res = static_cast<ID3D12Resource *>( whandle.com_obj );
|
||||
ComPtr<IMFMediaBuffer> spMediaBuffer;
|
||||
hr = MFCreateDXGISurfaceBuffer( __uuidof( ID3D12Resource ), pD3D12Res, 0, FALSE, &spMediaBuffer );
|
||||
|
||||
if( FAILED( hr ) )
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
|
||||
// Tell MF that this buffer is ready to use.
|
||||
ComPtr<IMFD3D12SynchronizationObjectCommands> spOutputSync; // needed to call Lock() for IMFMediaBuffer.
|
||||
ComPtr<IMFDXGIBuffer> 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() );
|
||||
}
|
||||
@@ -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 <vector>
|
||||
|
||||
#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 <unknwn.h>
|
||||
#include <windows.h>
|
||||
|
||||
#include <d3d12.h>
|
||||
#include <mfobjects.h>
|
||||
#include <mutex>
|
||||
#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<struct stats_buffer_manager_pool_entry> m_pool;
|
||||
};
|
||||
Reference in New Issue
Block a user