mediafoundation: Implement d3d12_context_queue_priority_manager and related ICodecAPI

Reviewed-by: Pohsiang (John) Hsu <pohhsu@microsoft.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/37376>
This commit is contained in:
Sil Vilerino 2025-09-04 14:32:13 -04:00 committed by Marge Bot
parent 11db73820f
commit 4b203d361e
7 changed files with 262 additions and 2 deletions

View file

@ -282,6 +282,14 @@ 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";
}
@ -405,6 +413,17 @@ CDX12EncHMFT::IsSupported( const GUID *Api )
}
}
#if ( USE_D3D12_PREVIEW_HEADERS && ( D3D12_PREVIEW_SDK_VERSION >= 717 ) )
if( (*Api == CODECAPI_AVEncWorkGlobalPriority) || (*Api == CODECAPI_AVEncWorkProcessPriority) )
{
if(m_EncoderCapabilities.m_bHWSupportsQueuePriorityManagement)
{
hr = S_OK;
return hr;
}
}
#endif // ( USE_D3D12_PREVIEW_HEADERS && ( D3D12_PREVIEW_SDK_VERSION >= 717 ) )
if( m_EncoderCapabilities.m_TwoPassSupport.bits.supports_1pass_recon_writing_skip )
{
if( *Api == CODECAPI_AVEncVideoRateControlFramePreAnalysisExternalReconDownscale )
@ -890,6 +909,18 @@ CDX12EncHMFT::GetValue( const GUID *Api, VARIANT *Value )
Value->vt = VT_BOOL;
Value->boolVal = m_bRateControlFramePreAnalysisExternalReconDownscale ? VARIANT_TRUE : VARIANT_FALSE;
}
#if ( USE_D3D12_PREVIEW_HEADERS && ( D3D12_PREVIEW_SDK_VERSION >= 717 ) )
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;
}
#endif // ( USE_D3D12_PREVIEW_HEADERS && ( D3D12_PREVIEW_SDK_VERSION >= 717 ) )
else if( *Api == CODECAPI_AVEncVideoInputDeltaQPBlockSettings )
{
InputQPSettings hevcDeltaQPSettings;
@ -1567,6 +1598,40 @@ 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 );
}
#if ( USE_D3D12_PREVIEW_HEADERS && ( D3D12_PREVIEW_SDK_VERSION >= 717 ) )
m_WorkProcessPriority = (D3D12_COMMAND_QUEUE_PROCESS_PRIORITY) (Value->ulVal);;
m_bWorkProcessPrioritySet = TRUE;
#endif // ( USE_D3D12_PREVIEW_HEADERS && ( D3D12_PREVIEW_SDK_VERSION >= 717 ) )
}
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 );
}
#if ( USE_D3D12_PREVIEW_HEADERS && ( D3D12_PREVIEW_SDK_VERSION >= 717 ) )
m_WorkGlobalPriority = (D3D12_COMMAND_QUEUE_GLOBAL_PRIORITY) Value->ulVal;
m_bWorkGlobalPrioritySet = TRUE;
#endif // ( USE_D3D12_PREVIEW_HEADERS && ( D3D12_PREVIEW_SDK_VERSION >= 717 ) )
}
else if( *Api == CODECAPI_AVEncVideoOutputQPMapBlockSize )
{
debug_printf( "[dx12 hmft 0x%p] SET CODECAPI_AVEncVideoOutputQPMapBlockSize - %u\n", this, Value->ulVal );

View file

@ -456,6 +456,40 @@ CDX12EncHMFT::PrepareForEncode( IMFSample *pSample, LPDX12EncodeContext *ppDX12E
pDX12EncodeContext->pVlScreen = m_pVlScreen; // weakref
#if ( USE_D3D12_PREVIEW_HEADERS && ( D3D12_PREVIEW_SDK_VERSION >= 717 ) )
//
// 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)
{
for (ID3D12CommandQueue* queue : m_ContextPriorityMgr.m_registeredQueues)
{
mtx_lock(&m_ContextPriorityMgr.m_lock);
int 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;
}
#endif // ( USE_D3D12_PREVIEW_HEADERS && ( D3D12_PREVIEW_SDK_VERSION >= 717 ) )
// Call the helper for encoder specific work
pDX12EncodeContext->encoderPicInfo.base.in_fence = pPipeEncoderInputFenceHandle;
pDX12EncodeContext->encoderPicInfo.base.in_fence_value = pipeEncoderInputFenceHandleValue;

View file

@ -22,6 +22,7 @@
*/
#include <utility>
#include <encoder_capabilities.h>
#include "gallium/drivers/d3d12/d3d12_interop_public.h"
// Initializes encoder capabilities by querying hardware-specific parameters from pipe given the video profile.
void
@ -153,4 +154,10 @@ encoder_capabilities::initialize( pipe_screen *pScreen, pipe_video_profile video
m_PSNRStatsSupport.value =
pScreen->get_video_param( pScreen, videoProfile, PIPE_VIDEO_ENTRYPOINT_ENCODE, PIPE_VIDEO_CAP_ENC_GPU_STATS_PSNR );
#if ( USE_D3D12_PREVIEW_HEADERS && ( D3D12_PREVIEW_SDK_VERSION >= 717 ) )
d3d12_interop_device_info1 screen_interop_info = {};
bool successQuery = pScreen->interop_query_device_info(pScreen, sizeof(d3d12_interop_device_info1), &screen_interop_info) != 0;
m_bHWSupportsQueuePriorityManagement = successQuery && screen_interop_info.set_context_queue_priority_manager != NULL;
#endif // ( USE_D3D12_PREVIEW_HEADERS && ( D3D12_PREVIEW_SDK_VERSION >= 717 ) )
}

View file

@ -134,4 +134,7 @@ class encoder_capabilities
// PSNR frame stats
union pipe_enc_cap_gpu_stats_psnr m_PSNRStatsSupport = {};
// Driver supports queue priority management
bool m_bHWSupportsQueuePriorityManagement = false;
};

View file

@ -504,6 +504,45 @@ 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"
@ -695,6 +734,13 @@ class __declspec( uuid( HMFT_GUID ) ) CDX12EncHMFT : CMFD3DManager,
BOOL m_bRateControlFramePreAnalysis = FALSE;
BOOL m_bRateControlFramePreAnalysisExternalReconDownscale = FALSE;
#if ( USE_D3D12_PREVIEW_HEADERS && ( D3D12_PREVIEW_SDK_VERSION >= 717 ) )
D3D12_COMMAND_QUEUE_PROCESS_PRIORITY m_WorkProcessPriority = {};
BOOL m_bWorkProcessPrioritySet = FALSE;
D3D12_COMMAND_QUEUE_GLOBAL_PRIORITY m_WorkGlobalPriority = {};
BOOL m_bWorkGlobalPrioritySet = FALSE;
#endif // ( USE_D3D12_PREVIEW_HEADERS && ( D3D12_PREVIEW_SDK_VERSION >= 717 ) )
struct pipe_video_codec *m_pPipeVideoCodec = nullptr;
struct pipe_video_codec *m_pPipeVideoBlitter = nullptr;
reference_frames_tracker *m_pGOPTracker = nullptr;

View file

@ -248,12 +248,71 @@ CMFD3DManager::UpdateGPUFeatureFlags()
*/
}
#if ( USE_D3D12_PREVIEW_HEADERS && ( D3D12_PREVIEW_SDK_VERSION >= 717 ) )
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 (FAILED(queue->QueryInterface(IID_PPV_ARGS( &queue_unknown ))))
{
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())
{
//
// Register the queue_unknown with the MFT.
//
mft_mgr->m_registeredQueues.push_back(queue);
}
mtx_unlock(&mft_mgr->m_lock);
return 0;
}
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 (FAILED(queue->QueryInterface(IID_PPV_ARGS( &queue_unknown ))))
{
mtx_unlock(&mft_mgr->m_lock);
return -1;
}
//
// Unregister the queue_unknown with the MFT.
//
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);
mtx_unlock(&mft_mgr->m_lock);
return 0;
}
#endif // ( USE_D3D12_PREVIEW_HEADERS && ( D3D12_PREVIEW_SDK_VERSION >= 717 ) )
HRESULT
CMFD3DManager::xOnSetD3DManager( ULONG_PTR ulParam )
{
HRESULT hr = S_OK;
Shutdown();
#if ( USE_D3D12_PREVIEW_HEADERS && ( D3D12_PREVIEW_SDK_VERSION >= 717 ) )
d3d12_interop_device_info1 screen_interop_info = {};
#endif // ( USE_D3D12_PREVIEW_HEADERS && ( D3D12_PREVIEW_SDK_VERSION >= 717 ) )
if( ulParam == 0 )
{
return hr;
@ -273,6 +332,36 @@ CMFD3DManager::xOnSetD3DManager( ULONG_PTR ulParam )
CHECKNULL_GOTO( m_pPipeContext = pipe_create_multimedia_context( m_pVlScreen->pscreen, false ),
MF_E_DXGI_DEVICE_NOT_INITIALIZED,
done );
#if ( USE_D3D12_PREVIEW_HEADERS && ( D3D12_PREVIEW_SDK_VERSION >= 717 ) )
if ((m_pVlScreen->pscreen->interop_query_device_info(m_pVlScreen->pscreen, sizeof(d3d12_interop_device_info1), &screen_interop_info) != 0) &&
(screen_interop_info.set_context_queue_priority_manager != NULL))
{
CHECKBOOL_GOTO( thrd_success == mtx_init(&m_ContextPriorityMgr.m_lock, mtx_plain),
MF_E_DXGI_DEVICE_NOT_INITIALIZED,
done );
m_ContextPriorityMgr.base.register_work_queue = MFTRegisterWorkQueue;
m_ContextPriorityMgr.base.unregister_work_queue = MFTUnregisterWorkQueue;
CHECKBOOL_GOTO( screen_interop_info.set_context_queue_priority_manager( m_pPipeContext, &m_ContextPriorityMgr.base ) == 0,
MF_E_DXGI_DEVICE_NOT_INITIALIZED,
done );
//
// Verify that the callbacks have been filled by the driver
//
CHECKNULL_GOTO( m_ContextPriorityMgr.base.context,
MF_E_DXGI_DEVICE_NOT_INITIALIZED,
done );
CHECKNULL_GOTO( m_ContextPriorityMgr.base.set_queue_priority,
MF_E_DXGI_DEVICE_NOT_INITIALIZED,
done );
CHECKNULL_GOTO( m_ContextPriorityMgr.base.get_queue_priority,
MF_E_DXGI_DEVICE_NOT_INITIALIZED,
done );
}
#endif // ( USE_D3D12_PREVIEW_HEADERS && ( D3D12_PREVIEW_SDK_VERSION >= 717 ) )
CHECKHR_GOTO( MFCreateVideoSampleAllocatorEx( IID_PPV_ARGS( &m_spVideoSampleAllocator ) ), done );
CHECKHR_GOTO( GetDeviceInfo(), done );

View file

@ -42,6 +42,9 @@
#include <mutex>
#include <wrl/client.h>
#include <wrl/implements.h>
#include <c11/threads.h>
#include <vector>
#include "gallium/drivers/d3d12/d3d12_interop_public.h"
#include "macros.h"
@ -65,6 +68,15 @@ typedef union
uint64_t version; // bits field
} MFAdapterDriverVersion;
#if ( USE_D3D12_PREVIEW_HEADERS && ( D3D12_PREVIEW_SDK_VERSION >= 717 ) )
struct mft_context_queue_priority_manager
{
struct d3d12_context_queue_priority_manager base;
std::vector<ID3D12CommandQueue*> m_registeredQueues;
mtx_t m_lock;
};
#endif // ( USE_D3D12_PREVIEW_HEADERS && ( D3D12_PREVIEW_SDK_VERSION >= 717 ) )
class CMFD3DManager
{
public:
@ -94,6 +106,10 @@ class CMFD3DManager
struct sw_winsys *m_pWinsys = nullptr;
struct pipe_context *m_pPipeContext = nullptr;
#if ( USE_D3D12_PREVIEW_HEADERS && ( D3D12_PREVIEW_SDK_VERSION >= 717 ) )
struct mft_context_queue_priority_manager m_ContextPriorityMgr = {};
#endif // ( USE_D3D12_PREVIEW_HEADERS && ( D3D12_PREVIEW_SDK_VERSION >= 717 ) )
uint32_t m_deviceVendorId {};
uint32_t m_deviceDeviceId {};
MFAdapterDriverVersion m_deviceDriverVersion {};