diff --git a/src/gallium/frontends/mediafoundation/codecapi.cpp b/src/gallium/frontends/mediafoundation/codecapi.cpp index ef656801baf..e3c4c379ef8 100644 --- a/src/gallium/frontends/mediafoundation/codecapi.cpp +++ b/src/gallium/frontends/mediafoundation/codecapi.cpp @@ -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 ); diff --git a/src/gallium/frontends/mediafoundation/encode.cpp b/src/gallium/frontends/mediafoundation/encode.cpp index 88c98bc2588..6e23addc0cb 100644 --- a/src/gallium/frontends/mediafoundation/encode.cpp +++ b/src/gallium/frontends/mediafoundation/encode.cpp @@ -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((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) + { + 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(&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; + } + +#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; diff --git a/src/gallium/frontends/mediafoundation/encoder_capabilities.cpp b/src/gallium/frontends/mediafoundation/encoder_capabilities.cpp index fd868f170a0..90d346f8386 100644 --- a/src/gallium/frontends/mediafoundation/encoder_capabilities.cpp +++ b/src/gallium/frontends/mediafoundation/encoder_capabilities.cpp @@ -22,6 +22,7 @@ */ #include #include +#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 ) ) } diff --git a/src/gallium/frontends/mediafoundation/encoder_capabilities.h b/src/gallium/frontends/mediafoundation/encoder_capabilities.h index 871049cb99c..9f33018cc4e 100644 --- a/src/gallium/frontends/mediafoundation/encoder_capabilities.h +++ b/src/gallium/frontends/mediafoundation/encoder_capabilities.h @@ -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; }; diff --git a/src/gallium/frontends/mediafoundation/hmft_entrypoints.h b/src/gallium/frontends/mediafoundation/hmft_entrypoints.h index c64998b616a..351f590e341 100644 --- a/src/gallium/frontends/mediafoundation/hmft_entrypoints.h +++ b/src/gallium/frontends/mediafoundation/hmft_entrypoints.h @@ -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; diff --git a/src/gallium/frontends/mediafoundation/mfd3dmanager.cpp b/src/gallium/frontends/mediafoundation/mfd3dmanager.cpp index d5b597ac12d..fe7ad5894c0 100644 --- a/src/gallium/frontends/mediafoundation/mfd3dmanager.cpp +++ b/src/gallium/frontends/mediafoundation/mfd3dmanager.cpp @@ -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 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 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; @@ -271,8 +330,38 @@ CMFD3DManager::xOnSetD3DManager( ULONG_PTR ulParam ) MF_E_DXGI_DEVICE_NOT_INITIALIZED, done ); CHECKNULL_GOTO( m_pPipeContext = pipe_create_multimedia_context( m_pVlScreen->pscreen, false ), - MF_E_DXGI_DEVICE_NOT_INITIALIZED, - done ); + 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 ); diff --git a/src/gallium/frontends/mediafoundation/mfd3dmanager.h b/src/gallium/frontends/mediafoundation/mfd3dmanager.h index cfb2f17856b..5f558006443 100644 --- a/src/gallium/frontends/mediafoundation/mfd3dmanager.h +++ b/src/gallium/frontends/mediafoundation/mfd3dmanager.h @@ -42,6 +42,9 @@ #include #include #include +#include +#include +#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 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 {};