From 2af4938328cffb88bb0a6c9132110d79ff1d9dc7 Mon Sep 17 00:00:00 2001 From: "Pohsiang (John) Hsu" Date: Fri, 10 Apr 2026 08:30:46 -0700 Subject: [PATCH] mediafoundation: add support for GPU priority setting via IMFDXGIScheduler Reviewed-by: Sil Vilerino Part-of: --- .../frontends/mediafoundation/codecapi.cpp | 57 ---------- .../frontends/mediafoundation/encode.cpp | 33 ------ .../mediafoundation/hmft_entrypoints.h | 45 -------- .../mediafoundation/mfd3dmanager.cpp | 102 +++++++++++++----- .../frontends/mediafoundation/mfd3dmanager.h | 54 +++++++++- 5 files changed, 128 insertions(+), 163 deletions(-) diff --git a/src/gallium/frontends/mediafoundation/codecapi.cpp b/src/gallium/frontends/mediafoundation/codecapi.cpp index f25f4fcebb5..512df11fd08 100644 --- a/src/gallium/frontends/mediafoundation/codecapi.cpp +++ b/src/gallium/frontends/mediafoundation/codecapi.cpp @@ -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 ); diff --git a/src/gallium/frontends/mediafoundation/encode.cpp b/src/gallium/frontends/mediafoundation/encode.cpp index 5ad36db308d..162b432639f 100644 --- a/src/gallium/frontends/mediafoundation/encode.cpp +++ b/src/gallium/frontends/mediafoundation/encode.cpp @@ -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((pipeEncoderInputFenceHandleValue % 14) + 18); // 18-31 range (no hard realtime privileges) - m_bWorkGlobalPrioritySet = ((pipeEncoderInputFenceHandleValue % 2) == 0) ? TRUE : FALSE; - m_WorkProcessPriority = static_cast(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( &m_WorkGlobalPriority ), - reinterpret_cast( &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; diff --git a/src/gallium/frontends/mediafoundation/hmft_entrypoints.h b/src/gallium/frontends/mediafoundation/hmft_entrypoints.h index 26ec5fa8dfc..6a19391fc13 100644 --- a/src/gallium/frontends/mediafoundation/hmft_entrypoints.h +++ b/src/gallium/frontends/mediafoundation/hmft_entrypoints.h @@ -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; diff --git a/src/gallium/frontends/mediafoundation/mfd3dmanager.cpp b/src/gallium/frontends/mediafoundation/mfd3dmanager.cpp index f42f58f00e0..4c22c9b4341 100644 --- a/src/gallium/frontends/mediafoundation/mfd3dmanager.cpp +++ b/src/gallium/frontends/mediafoundation/mfd3dmanager.cpp @@ -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 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 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 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 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 ); diff --git a/src/gallium/frontends/mediafoundation/mfd3dmanager.h b/src/gallium/frontends/mediafoundation/mfd3dmanager.h index 8c586e6bcbf..e5408a29a15 100644 --- a/src/gallium/frontends/mediafoundation/mfd3dmanager.h +++ b/src/gallium/frontends/mediafoundation/mfd3dmanager.h @@ -45,6 +45,7 @@ #include #include #include +#include #include "macros.h" @@ -53,6 +54,54 @@ // Use the Windows SDK dxcore include (e.g directx/dxcore uses DirectX-Headers) #include +// 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 m_registeredQueues; + std::unordered_map> m_registeredQueues; + ComPtr m_spSchedulerClient; + HANDLE m_hDevice = NULL; mtx_t m_lock; + const void *m_logId = {}; }; class CMFD3DManager