mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-07 09:18:04 +02:00
mediafoundation: add support for GPU priority setting via IMFDXGIScheduler
Reviewed-by: Sil Vilerino <sivileri@microsoft.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/40895>
This commit is contained in:
parent
06c9c08c48
commit
2af4938328
5 changed files with 128 additions and 163 deletions
|
|
@ -290,14 +290,6 @@ StringFromCodecAPI( const GUID *Api )
|
|||
{
|
||||
return "CODECAPI_AVEncVideoInputAbsoluteQPBlockSettings";
|
||||
}
|
||||
else if( *Api == CODECAPI_AVEncWorkGlobalPriority )
|
||||
{
|
||||
return "CODECAPI_AVEncWorkGlobalPriority";
|
||||
}
|
||||
else if( *Api == CODECAPI_AVEncWorkProcessPriority )
|
||||
{
|
||||
return "CODECAPI_AVEncWorkProcessPriority";
|
||||
}
|
||||
return "Unknown CodecAPI";
|
||||
}
|
||||
|
||||
|
|
@ -430,15 +422,6 @@ CDX12EncHMFT::IsSupported( const GUID *Api )
|
|||
}
|
||||
}
|
||||
|
||||
if( ( *Api == CODECAPI_AVEncWorkGlobalPriority ) || ( *Api == CODECAPI_AVEncWorkProcessPriority ) )
|
||||
{
|
||||
if( m_EncoderCapabilities.m_bHWSupportsQueuePriorityManagement )
|
||||
{
|
||||
hr = S_OK;
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
|
||||
if( m_EncoderCapabilities.m_TwoPassSupport.bits.supports_1pass_recon_writing_skip )
|
||||
{
|
||||
if( *Api == CODECAPI_AVEncVideoRateControlFramePreAnalysisExternalReconDownscale )
|
||||
|
|
@ -966,16 +949,6 @@ CDX12EncHMFT::GetValue( const GUID *Api, VARIANT *Value )
|
|||
Value->vt = VT_UI4;
|
||||
Value->ulVal = m_uiSliceGenerationMode;
|
||||
}
|
||||
else if( *Api == CODECAPI_AVEncWorkGlobalPriority )
|
||||
{
|
||||
Value->vt = VT_UI4;
|
||||
Value->ulVal = (UINT32) m_WorkGlobalPriority;
|
||||
}
|
||||
else if( *Api == CODECAPI_AVEncWorkProcessPriority )
|
||||
{
|
||||
Value->vt = VT_UI4;
|
||||
Value->ulVal = (UINT32) m_WorkProcessPriority;
|
||||
}
|
||||
else if( *Api == CODECAPI_AVEncVideoInputDeltaQPBlockSettings )
|
||||
{
|
||||
InputQPSettings hevcDeltaQPSettings;
|
||||
|
|
@ -1731,36 +1704,6 @@ CDX12EncHMFT::SetValue( const GUID *Api, VARIANT *Value )
|
|||
}
|
||||
m_bVideoEnableSpatialAdaptiveQuantization = Value->ulVal ? TRUE : FALSE;
|
||||
}
|
||||
else if( *Api == CODECAPI_AVEncWorkProcessPriority )
|
||||
{
|
||||
debug_printf( "[dx12 hmft 0x%p] SET CODECAPI_AVEncWorkProcessPriority - %u\n", this, Value->ulVal );
|
||||
if( Value->vt != VT_UI4 )
|
||||
{
|
||||
CHECKHR_GOTO( E_INVALIDARG, done );
|
||||
}
|
||||
|
||||
if( !m_EncoderCapabilities.m_bHWSupportsQueuePriorityManagement )
|
||||
{
|
||||
CHECKHR_GOTO( E_INVALIDARG, done );
|
||||
}
|
||||
m_WorkProcessPriority = (D3D12_COMMAND_QUEUE_PROCESS_PRIORITY) ( Value->ulVal );
|
||||
m_bWorkProcessPrioritySet = TRUE;
|
||||
}
|
||||
else if( *Api == CODECAPI_AVEncWorkGlobalPriority )
|
||||
{
|
||||
debug_printf( "[dx12 hmft 0x%p] SET CODECAPI_AVEncWorkGlobalPriority - %u\n", this, Value->ulVal );
|
||||
if( Value->vt != VT_UI4 )
|
||||
{
|
||||
CHECKHR_GOTO( E_INVALIDARG, done );
|
||||
}
|
||||
|
||||
if( !m_EncoderCapabilities.m_bHWSupportsQueuePriorityManagement )
|
||||
{
|
||||
CHECKHR_GOTO( E_INVALIDARG, done );
|
||||
}
|
||||
m_WorkGlobalPriority = (D3D12_COMMAND_QUEUE_GLOBAL_PRIORITY) Value->ulVal;
|
||||
m_bWorkGlobalPrioritySet = TRUE;
|
||||
}
|
||||
else if( *Api == CODECAPI_AVEncVideoOutputQPMapBlockSize )
|
||||
{
|
||||
debug_printf( "[dx12 hmft 0x%p] SET CODECAPI_AVEncVideoOutputQPMapBlockSize - %u\n", this, Value->ulVal );
|
||||
|
|
|
|||
|
|
@ -522,39 +522,6 @@ CDX12EncHMFT::PrepareForEncode( IMFSample *pSample, LPDX12EncodeContext *ppDX12E
|
|||
|
||||
pDX12EncodeContext->pVlScreen = m_pVlScreen; // weakref
|
||||
|
||||
//
|
||||
// Update the encoder priorities (if any set)
|
||||
//
|
||||
|
||||
#if 0 // For testing priorities
|
||||
{
|
||||
m_bWorkProcessPrioritySet = ((pipeEncoderInputFenceHandleValue % 2) == 0) ? TRUE : FALSE;
|
||||
m_WorkGlobalPriority = static_cast<D3D12_COMMAND_QUEUE_GLOBAL_PRIORITY>((pipeEncoderInputFenceHandleValue % 14) + 18); // 18-31 range (no hard realtime privileges)
|
||||
m_bWorkGlobalPrioritySet = ((pipeEncoderInputFenceHandleValue % 2) == 0) ? TRUE : FALSE;
|
||||
m_WorkProcessPriority = static_cast<D3D12_COMMAND_QUEUE_PROCESS_PRIORITY>(pipeEncoderInputFenceHandleValue % 2); // 0-1 range
|
||||
}
|
||||
#endif // For testing priorities
|
||||
|
||||
if( m_bWorkProcessPrioritySet || m_bWorkGlobalPrioritySet )
|
||||
{
|
||||
mtx_lock( &m_ContextPriorityMgr.m_lock );
|
||||
int result = 0;
|
||||
for( ID3D12CommandQueue *queue : m_ContextPriorityMgr.m_registeredQueues )
|
||||
{
|
||||
result = m_ContextPriorityMgr.base.set_queue_priority( &m_ContextPriorityMgr.base,
|
||||
queue,
|
||||
reinterpret_cast<uint32_t *>( &m_WorkGlobalPriority ),
|
||||
reinterpret_cast<uint32_t *>( &m_WorkProcessPriority ) );
|
||||
}
|
||||
mtx_unlock( &m_ContextPriorityMgr.m_lock );
|
||||
CHECKBOOL_GOTO( result == 0, MF_E_UNEXPECTED, done );
|
||||
|
||||
// Once set in the underlying pipe context, don't set them again
|
||||
// until they're modified by the CodecAPI SetValue function.
|
||||
m_bWorkProcessPrioritySet = FALSE;
|
||||
m_bWorkGlobalPrioritySet = FALSE;
|
||||
}
|
||||
|
||||
// Call the helper for encoder specific work
|
||||
pDX12EncodeContext->encoderPicInfo.base.in_fence = pPipeEncoderInputFenceHandle;
|
||||
pDX12EncodeContext->encoderPicInfo.base.in_fence_value = pipeEncoderInputFenceHandleValue;
|
||||
|
|
|
|||
|
|
@ -439,46 +439,6 @@ DEFINE_CODECAPI_GUID( AVEncVideoRateControlFramePreAnalysisExternalReconDownscal
|
|||
DEFINE_CODECAPI_GUIDNAMED( AVEncVideoRateControlFramePreAnalysisExternalReconDownscale )
|
||||
#endif
|
||||
|
||||
#ifndef CODECAPI_AVEncWorkGlobalPriority
|
||||
// AVEncWorkGlobalPriority (VT_UI4) (Experimental, Testing only)
|
||||
// Indicates global priority for all work submitted by the encoder to the GPU
|
||||
// VARIANT_FALSE: disable; VARIANT_TRUE: enable
|
||||
DEFINE_CODECAPI_GUID( AVEncWorkGlobalPriority,
|
||||
"CA123CAA-A17B-4BBA-9E08-269F3CF5D636",
|
||||
0xca123caa,
|
||||
0xa17b,
|
||||
0x4bba,
|
||||
0x9e,
|
||||
0x8,
|
||||
0x26,
|
||||
0x9f,
|
||||
0x3c,
|
||||
0xf5,
|
||||
0xd6,
|
||||
0x36 )
|
||||
#define CODECAPI_AVEncWorkGlobalPriority DEFINE_CODECAPI_GUIDNAMED( AVEncWorkGlobalPriority )
|
||||
#endif
|
||||
|
||||
#ifndef CODECAPI_AVEncWorkProcessPriority
|
||||
// AVEncWorkProcessPriority (VT_UI4) (Experimental, Testing only)
|
||||
// Indicates global priority for all work submitted by the encoder to the GPU
|
||||
// VARIANT_FALSE: disable; VARIANT_TRUE: enable
|
||||
DEFINE_CODECAPI_GUID( AVEncWorkProcessPriority,
|
||||
"FB123CAA-B778-4BBA-9E08-269F3CF5D125",
|
||||
0xfb123caa,
|
||||
0xb778,
|
||||
0x4bba,
|
||||
0x9e,
|
||||
0x8,
|
||||
0x26,
|
||||
0x9f,
|
||||
0x3c,
|
||||
0xf5,
|
||||
0xd1,
|
||||
0x25 )
|
||||
#define CODECAPI_AVEncWorkProcessPriority DEFINE_CODECAPI_GUIDNAMED( AVEncWorkProcessPriority )
|
||||
#endif
|
||||
|
||||
#if MFT_CODEC_H264ENC
|
||||
#define HMFT_GUID "8994db7c-288a-4c62-a136-a3c3c2a208a8"
|
||||
#elif MFT_CODEC_H265ENC
|
||||
|
|
@ -720,11 +680,6 @@ class __declspec( uuid( HMFT_GUID ) ) CDX12EncHMFT : CMFD3DManager,
|
|||
BOOL m_bRateControlFramePreAnalysis = FALSE;
|
||||
BOOL m_bRateControlFramePreAnalysisExternalReconDownscale = FALSE;
|
||||
|
||||
D3D12_COMMAND_QUEUE_PROCESS_PRIORITY m_WorkProcessPriority = {};
|
||||
BOOL m_bWorkProcessPrioritySet = FALSE;
|
||||
D3D12_COMMAND_QUEUE_GLOBAL_PRIORITY m_WorkGlobalPriority = {};
|
||||
BOOL m_bWorkGlobalPrioritySet = FALSE;
|
||||
|
||||
UINT m_uiMaxOutputBitstreamSize = 0u;
|
||||
struct pipe_video_codec *m_pPipeVideoCodec = nullptr;
|
||||
struct pipe_video_codec *m_pPipeVideoBlitter = nullptr;
|
||||
|
|
|
|||
|
|
@ -92,6 +92,11 @@ CMFD3DManager::Shutdown( bool bReleaseDeviceManager )
|
|||
m_spReconstructedPictureBufferPool.Reset();
|
||||
}
|
||||
|
||||
// Release scheduler registrations before closing the device handle
|
||||
m_ContextPriorityMgr.m_registeredQueues.clear();
|
||||
m_ContextPriorityMgr.m_spSchedulerClient.Reset();
|
||||
m_ContextPriorityMgr.m_hDevice = NULL;
|
||||
|
||||
if( m_spDeviceManager != nullptr )
|
||||
{
|
||||
if( m_hDevice != NULL )
|
||||
|
|
@ -277,7 +282,7 @@ CMFD3DManager::UpdateGPUFeatureFlags()
|
|||
m_deviceDriverVersion.part4 >= 9002 )
|
||||
{
|
||||
m_gpuFeatureFlags.m_bH264SendUnwrappedPOC = true;
|
||||
MFE_INFO( "[dx12 hmft 0x%p] D3DManager: GPUFeature m_bH264SendUnwrappedPOC is set to true\n", m_logId );
|
||||
MFE_INFO( "[dx12 hmft 0x%p] D3DManager: GPUFeature m_bH264SendUnwrappedPOC is set to true", m_logId );
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
|
@ -287,27 +292,38 @@ int
|
|||
MFTRegisterWorkQueue( struct d3d12_context_queue_priority_manager *manager, ID3D12CommandQueue *queue )
|
||||
{
|
||||
mft_context_queue_priority_manager *mft_mgr = (mft_context_queue_priority_manager *) manager;
|
||||
mtx_lock( &mft_mgr->m_lock );
|
||||
|
||||
ComPtr<IUnknown> queue_unknown;
|
||||
if( !queue ||
|
||||
FAILED( queue->QueryInterface( IID_PPV_ARGS( &queue_unknown ) ) ) )
|
||||
if( !queue )
|
||||
{
|
||||
mtx_unlock( &mft_mgr->m_lock );
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Only register the queue if not already registered
|
||||
auto it = std::find( mft_mgr->m_registeredQueues.begin(), mft_mgr->m_registeredQueues.end(), queue );
|
||||
if( it == mft_mgr->m_registeredQueues.end() )
|
||||
mtx_lock( &mft_mgr->m_lock );
|
||||
|
||||
if( mft_mgr->m_spSchedulerClient )
|
||||
{
|
||||
//
|
||||
// Register the queue_unknown with the MFT.
|
||||
//
|
||||
if( mft_mgr->m_registeredQueues.find( queue ) == mft_mgr->m_registeredQueues.end() )
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
ComPtr<IMFDXGISchedulerRegistration> spRegistration;
|
||||
|
||||
mft_mgr->m_registeredQueues.push_back( queue );
|
||||
hr = mft_mgr->m_spSchedulerClient->RegisterObject( mft_mgr->m_hDevice, queue, &spRegistration );
|
||||
if( FAILED( hr ) )
|
||||
{
|
||||
MFE_ERROR( "[dx12 hmft 0x%p] D3DManager: RegisterObject failed for Queue 0x%p", mft_mgr->m_logId, queue );
|
||||
mtx_unlock( &mft_mgr->m_lock );
|
||||
return -1;
|
||||
}
|
||||
MFE_INFO( "[dx12 hmft 0x%p] D3DManager: RegisterObject succeeded for Queue 0x%p, spRegistration 0x%p",
|
||||
mft_mgr->m_logId,
|
||||
queue,
|
||||
spRegistration.Get() );
|
||||
mft_mgr->m_registeredQueues[queue] = spRegistration;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MFE_INFO( "[dx12 hmft 0x%p] D3DManager: m_spSchedulerClient is not supported -> no opt", mft_mgr->m_logId );
|
||||
}
|
||||
|
||||
mtx_unlock( &mft_mgr->m_lock );
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -316,24 +332,47 @@ int
|
|||
MFTUnregisterWorkQueue( struct d3d12_context_queue_priority_manager *manager, ID3D12CommandQueue *queue )
|
||||
{
|
||||
mft_context_queue_priority_manager *mft_mgr = (mft_context_queue_priority_manager *) manager;
|
||||
mtx_lock( &mft_mgr->m_lock );
|
||||
|
||||
ComPtr<IUnknown> queue_unknown;
|
||||
if( !queue ||
|
||||
FAILED( queue->QueryInterface( IID_PPV_ARGS( &queue_unknown ) ) ) )
|
||||
if( !queue )
|
||||
{
|
||||
mtx_unlock( &mft_mgr->m_lock );
|
||||
return -1;
|
||||
}
|
||||
|
||||
//
|
||||
// Unregister the queue_unknown with the MFT.
|
||||
//
|
||||
mtx_lock( &mft_mgr->m_lock );
|
||||
if( mft_mgr->m_spSchedulerClient )
|
||||
{
|
||||
auto item = mft_mgr->m_registeredQueues.find( queue );
|
||||
if( item != mft_mgr->m_registeredQueues.end() )
|
||||
{
|
||||
MFE_INFO( "[dx12 hmft 0x%p] D3DManager: Releases spRegistration for Queue 0x%p, spRegistration 0x%p",
|
||||
mft_mgr->m_logId,
|
||||
queue,
|
||||
item->second.Get() );
|
||||
|
||||
auto it = std::find( mft_mgr->m_registeredQueues.begin(), mft_mgr->m_registeredQueues.end(), queue );
|
||||
if( it != mft_mgr->m_registeredQueues.end() )
|
||||
mft_mgr->m_registeredQueues.erase( it );
|
||||
#if MESA_DEBUG
|
||||
{
|
||||
uint32_t global_priority, local_priority;
|
||||
mft_mgr->base.get_queue_priority( &mft_mgr->base, queue, &global_priority, &local_priority );
|
||||
debug_printf( "[dx12 hmft 0x%p] D3DManager: ending queue = 0x%p, local_priority = %d, global_priority = %d\n",
|
||||
mft_mgr->m_logId,
|
||||
queue,
|
||||
local_priority,
|
||||
global_priority );
|
||||
}
|
||||
#endif
|
||||
|
||||
mft_mgr->m_registeredQueues.erase( item );
|
||||
}
|
||||
else
|
||||
{
|
||||
MFE_WARNING( "[dx12 hmft 0x%p] D3DManager: Queue 0x%p is unexpectedly not found in m_registeredQueues",
|
||||
mft_mgr->m_logId,
|
||||
queue );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MFE_INFO( "[dx12 hmft 0x%p] D3DManager: m_spSchedulerClient is not supported -> no opt", mft_mgr->m_logId );
|
||||
}
|
||||
mtx_unlock( &mft_mgr->m_lock );
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -372,9 +411,18 @@ CMFD3DManager::xOnSetD3DManager( ULONG_PTR ulParam )
|
|||
{
|
||||
CHECKBOOL_GOTO( thrd_success == mtx_init( &m_ContextPriorityMgr.m_lock, mtx_plain ), MF_E_DXGI_DEVICE_NOT_INITIALIZED, done );
|
||||
|
||||
m_ContextPriorityMgr.m_logId = m_logId;
|
||||
m_ContextPriorityMgr.base.register_work_queue = MFTRegisterWorkQueue;
|
||||
m_ContextPriorityMgr.base.unregister_work_queue = MFTUnregisterWorkQueue;
|
||||
|
||||
// Query for scheduler client to register driver work queues with the MF scheduler
|
||||
ComPtr<IMFDXGISchedulerClient> spScheduler;
|
||||
if( SUCCEEDED( m_spDeviceManager->GetVideoService( m_hDevice, IID_PPV_ARGS( &spScheduler ) ) ) )
|
||||
{
|
||||
m_ContextPriorityMgr.m_spSchedulerClient = spScheduler;
|
||||
m_ContextPriorityMgr.m_hDevice = m_hDevice;
|
||||
}
|
||||
|
||||
CHECKBOOL_GOTO( m_ScreenInteropInfo.set_context_queue_priority_manager( m_pPipeContext, &m_ContextPriorityMgr.base ) == 0,
|
||||
MF_E_DXGI_DEVICE_NOT_INITIALIZED,
|
||||
done );
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@
|
|||
#include <c11/threads.h>
|
||||
#include <wrl/client.h>
|
||||
#include <wrl/implements.h>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "macros.h"
|
||||
|
||||
|
|
@ -53,6 +54,54 @@
|
|||
// Use the Windows SDK dxcore include (e.g directx/dxcore uses DirectX-Headers)
|
||||
#include <dxcore.h>
|
||||
|
||||
// Forward declare experimental MF DXGI Scheduler interfaces (not yet in all SDK versions)
|
||||
#ifndef __IMFDXGISchedulerRegistration_INTERFACE_DEFINED__
|
||||
#define __IMFDXGISchedulerRegistration_INTERFACE_DEFINED__
|
||||
|
||||
typedef enum MF_DXGI_SCHEDULING_PRIORITY
|
||||
{
|
||||
MF_DXGI_SCHEDULING_PRIORITY_IDLE = 0,
|
||||
MF_DXGI_SCHEDULING_PRIORITY_DEFAULT = 0x1,
|
||||
MF_DXGI_SCHEDULING_PRIORITY_HIGH = 0x2
|
||||
} MF_DXGI_SCHEDULING_PRIORITY;
|
||||
|
||||
/* interface IMFDXGISchedulerRegistration */
|
||||
/* [uuid][local][object] */
|
||||
|
||||
EXTERN_C const IID IID_IMFDXGISchedulerRegistration;
|
||||
|
||||
MIDL_INTERFACE( "396ACD9A-C9EF-41e5-8009-6735C0528875" )
|
||||
IMFDXGISchedulerRegistration : public IUnknown
|
||||
{
|
||||
public:
|
||||
virtual HRESULT STDMETHODCALLTYPE GetPriority(
|
||||
/* [annotation][out] */
|
||||
_Out_ MF_DXGI_SCHEDULING_PRIORITY * priority ) = 0;
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE SetPriority(
|
||||
/* [in] */ MF_DXGI_SCHEDULING_PRIORITY priority ) = 0;
|
||||
};
|
||||
|
||||
/* interface IMFDXGISchedulerClient */
|
||||
/* [uuid][local][object] */
|
||||
|
||||
EXTERN_C const IID IID_IMFDXGISchedulerClient;
|
||||
|
||||
MIDL_INTERFACE( "DF681668-70EC-457B-9AA3-CAA60910A710" )
|
||||
IMFDXGISchedulerClient : public IUnknown
|
||||
{
|
||||
public:
|
||||
virtual HRESULT STDMETHODCALLTYPE RegisterObject(
|
||||
/* [annotation][in] */
|
||||
_In_ HANDLE hDevice,
|
||||
/* [annotation][in] */
|
||||
_In_ IUnknown * pObject,
|
||||
/* [annotation][out] */
|
||||
_COM_Outptr_ IMFDXGISchedulerRegistration * *ppRegistration ) = 0;
|
||||
};
|
||||
#endif
|
||||
// end: Forward declare experimental MF DXGI Scheduler interfaces (not yet in all SDK versions)
|
||||
|
||||
using namespace Microsoft::WRL;
|
||||
using Microsoft::WRL::ComPtr;
|
||||
using namespace std;
|
||||
|
|
@ -73,8 +122,11 @@ typedef union
|
|||
struct mft_context_queue_priority_manager
|
||||
{
|
||||
struct d3d12_context_queue_priority_manager base;
|
||||
std::vector<ID3D12CommandQueue *> m_registeredQueues;
|
||||
std::unordered_map<ID3D12CommandQueue *, ComPtr<IMFDXGISchedulerRegistration>> m_registeredQueues;
|
||||
ComPtr<IMFDXGISchedulerClient> m_spSchedulerClient;
|
||||
HANDLE m_hDevice = NULL;
|
||||
mtx_t m_lock;
|
||||
const void *m_logId = {};
|
||||
};
|
||||
|
||||
class CMFD3DManager
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue