mediafoundation: Add AVEncVideoReconstructedPictureOutputMode and MFSampleExtension_VideoEncodeReconstructedPicture
Reviewed-by: Pohsiang (John) Hsu <pohhsu@microsoft.com> Reviewed-by: Yubo Xie <yuboxie@microsoft.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/38144>
This commit is contained in:
committed by
Marge Bot
parent
0953924dbe
commit
4169a7f36a
@@ -266,6 +266,10 @@ StringFromCodecAPI( const GUID *Api )
|
||||
{
|
||||
return "CODECAPI_AVEncVideoSatdMapBlockSize";
|
||||
}
|
||||
else if( *Api == CODECAPI_AVEncVideoReconstructedPictureOutputMode )
|
||||
{
|
||||
return "CODECAPI_AVEncVideoReconstructedPictureOutputMode";
|
||||
}
|
||||
else if( *Api == CODECAPI_AVEncVideoRateControlFramePreAnalysis )
|
||||
{
|
||||
return "CODECAPI_AVEncVideoRateControlFramePreAnalysis";
|
||||
@@ -444,6 +448,15 @@ CDX12EncHMFT::IsSupported( const GUID *Api )
|
||||
}
|
||||
}
|
||||
|
||||
if( m_EncoderCapabilities.m_bHWSupportReadableReconstructedPicture )
|
||||
{
|
||||
if( *Api == CODECAPI_AVEncVideoReconstructedPictureOutputMode )
|
||||
{
|
||||
hr = S_OK;
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
|
||||
if( m_EncoderCapabilities.m_HWSupportsVideoEncodeROI.bits.roi_rc_qp_delta_support )
|
||||
{
|
||||
if( *Api == CODECAPI_AVEncVideoInputDeltaQPBlockSettings )
|
||||
@@ -906,6 +919,11 @@ CDX12EncHMFT::GetValue( const GUID *Api, VARIANT *Value )
|
||||
Value->vt = VT_UI4;
|
||||
Value->ulVal = m_bVideoEnableFramePsnrYuv;
|
||||
}
|
||||
else if( *Api == CODECAPI_AVEncVideoReconstructedPictureOutputMode )
|
||||
{
|
||||
Value->vt = VT_UI4;
|
||||
Value->ulVal = (UINT32)m_VideoReconstructedPictureMode;
|
||||
}
|
||||
else if( *Api == CODECAPI_AVEncVideoEnableSpatialAdaptiveQuantization )
|
||||
{
|
||||
Value->vt = VT_UI4;
|
||||
@@ -1180,6 +1198,15 @@ CDX12EncHMFT::SetValue( const GUID *Api, VARIANT *Value )
|
||||
{
|
||||
m_bLowLatency = TRUE;
|
||||
}
|
||||
|
||||
// Enforce disabling read only shared resource output mode when low latency is disabled
|
||||
if ((m_bLowLatency == FALSE) &&
|
||||
(m_VideoReconstructedPictureMode == RECON_PIC_OUTPUT_MODE_READ_ONLY_SHARED_RESOURCE))
|
||||
{
|
||||
m_VideoReconstructedPictureMode = RECON_PIC_OUTPUT_MODE_DISABLED;
|
||||
debug_printf("[dx12 hmft 0x%p] Disabling RECON_PIC_OUTPUT_MODE_READ_ONLY_SHARED_RESOURCE as low latency is disabled. "
|
||||
"Please use to RECON_PIC_OUTPUT_MODE_BLIT_COPY for LowLatency Mode disabled scenarios.\n", this);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( *Api == CODECAPI_AVEncH264CABACEnable )
|
||||
@@ -1661,6 +1688,37 @@ CDX12EncHMFT::SetValue( const GUID *Api, VARIANT *Value )
|
||||
}
|
||||
m_bVideoEnableFramePsnrYuv = Value->ulVal ? TRUE : FALSE;
|
||||
}
|
||||
else if( *Api == CODECAPI_AVEncVideoReconstructedPictureOutputMode )
|
||||
{
|
||||
debug_printf( "[dx12 hmft 0x%p] SET CODECAPI_AVEncVideoReconstructedPictureOutputMode - %u\n", this, Value->ulVal );
|
||||
if( Value->vt != VT_UI4 )
|
||||
{
|
||||
CHECKHR_GOTO( E_INVALIDARG, done );
|
||||
}
|
||||
|
||||
if( Value->ulVal > RECON_PIC_OUTPUT_MODE_READ_ONLY_SHARED_RESOURCE )
|
||||
{
|
||||
MFE_ERROR( "[dx12 hmft 0x%p] Invalid value %u for CODECAPI_AVEncVideoReconstructedPictureOutputMode. Valid values are 0-2.",
|
||||
this, Value->ulVal );
|
||||
CHECKHR_GOTO( E_INVALIDARG, done );
|
||||
}
|
||||
|
||||
if ( !m_EncoderCapabilities.m_bHWSupportReadableReconstructedPicture && Value->ulVal != RECON_PIC_OUTPUT_MODE_DISABLED )
|
||||
{
|
||||
MFE_ERROR( "[dx12 hmft 0x%p] User tried to enable CODECAPI_AVEncVideoReconstructedPictureOutputMode, but this encoder "
|
||||
"does NOT support this feature.",
|
||||
this );
|
||||
CHECKHR_GOTO( E_INVALIDARG, done );
|
||||
}
|
||||
|
||||
if ( Value->ulVal == RECON_PIC_OUTPUT_MODE_READ_ONLY_SHARED_RESOURCE && !m_bLowLatency )
|
||||
{
|
||||
MFE_ERROR( "[dx12 hmft 0x%p] RECON_PIC_OUTPUT_MODE_READ_ONLY_SHARED_RESOURCE requires low latency mode to be enabled.",
|
||||
this );
|
||||
CHECKHR_GOTO( E_INVALIDARG, done );
|
||||
}
|
||||
m_VideoReconstructedPictureMode = (RECON_PIC_OUTPUT_MODE)Value->ulVal;
|
||||
}
|
||||
else if( *Api == CODECAPI_AVEncVideoEnableSpatialAdaptiveQuantization )
|
||||
{
|
||||
debug_printf( "[dx12 hmft 0x%p] SET CODECAPI_AVEncVideoEnableSpatialAdaptiveQuantization - %u\n", this, Value->ulVal );
|
||||
|
||||
@@ -47,6 +47,11 @@ typedef class DX12EncodeContext
|
||||
pipe_resource *pPipeResourceSATDMapStats = nullptr;
|
||||
pipe_resource *pPipeResourceRCBitAllocMapStats = nullptr;
|
||||
pipe_resource *pPipeResourcePSNRStats = nullptr;
|
||||
pipe_resource *pPipeResourceReconstructedPicture = nullptr;
|
||||
UINT PipeResourceReconstructedPictureSubresource = 0;
|
||||
pipe_fence_handle *pPipeFenceReconstructedPictureCompletionFence = NULL;
|
||||
ComPtr<ID3D12Fence> spReconstructedPictureCompletionFence;
|
||||
UINT64 ReconstructedPictureCompletionFenceValue = 0;
|
||||
|
||||
// Keep all the media and sync objects until encode is done
|
||||
// and then signal EnqueueResourceRelease so the media
|
||||
@@ -82,6 +87,43 @@ typedef class DX12EncodeContext
|
||||
((m_Codec == D3D12_VIDEO_ENCODER_CODEC_HEVC) && (encoderPicInfo.h265enc.slice_mode == PIPE_VIDEO_SLICE_MODE_AUTO));
|
||||
}
|
||||
|
||||
pipe_video_buffer *get_current_dpb_pic_buffer()
|
||||
{
|
||||
pipe_video_buffer* vid_buf = nullptr;
|
||||
|
||||
switch( m_Codec )
|
||||
{
|
||||
case D3D12_VIDEO_ENCODER_CODEC_H264:
|
||||
if (encoderPicInfo.h264enc.not_referenced) return nullptr;
|
||||
vid_buf = encoderPicInfo.h264enc.dpb[encoderPicInfo.h264enc.dpb_curr_pic].buffer;
|
||||
break;
|
||||
case D3D12_VIDEO_ENCODER_CODEC_HEVC:
|
||||
if (encoderPicInfo.h265enc.not_referenced) return nullptr;
|
||||
vid_buf = encoderPicInfo.h265enc.dpb[encoderPicInfo.h265enc.dpb_curr_pic].buffer;
|
||||
break;
|
||||
case D3D12_VIDEO_ENCODER_CODEC_AV1:
|
||||
if (encoderPicInfo.av1enc.refresh_frame_flags == 0) return nullptr;
|
||||
vid_buf = encoderPicInfo.av1enc.dpb[encoderPicInfo.av1enc.dpb_curr_pic].buffer;
|
||||
break;
|
||||
}
|
||||
|
||||
return vid_buf;
|
||||
}
|
||||
|
||||
pipe_resource *get_current_dpb_pic_resource()
|
||||
{
|
||||
pipe_video_buffer* vid_buf = get_current_dpb_pic_buffer();
|
||||
if (vid_buf)
|
||||
{
|
||||
struct pipe_resource *buf_resources[VL_NUM_COMPONENTS];
|
||||
memset(buf_resources, 0, sizeof(buf_resources));
|
||||
vid_buf->get_resources( vid_buf, &buf_resources[0] );
|
||||
assert(buf_resources[0]);
|
||||
return buf_resources[0];
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const D3D12_VIDEO_ENCODER_CODEC m_Codec = D3D12_VIDEO_ENCODER_CODEC_H264;
|
||||
UINT32 GetPictureType()
|
||||
{
|
||||
@@ -220,5 +262,7 @@ typedef class DX12EncodeContext
|
||||
pVlScreen->pscreen->resource_destroy( pVlScreen->pscreen, pPipeResourcePSNRStats );
|
||||
if( pDownscaledTwoPassPipeVideoBufferCompletionFence )
|
||||
pVlScreen->pscreen->fence_reference( pVlScreen->pscreen, &pDownscaledTwoPassPipeVideoBufferCompletionFence, NULL );
|
||||
if ( pPipeFenceReconstructedPictureCompletionFence )
|
||||
pVlScreen->pscreen->fence_reference( pVlScreen->pscreen, &pPipeFenceReconstructedPictureCompletionFence, NULL );
|
||||
}
|
||||
} *LPDX12EncodeContext;
|
||||
|
||||
@@ -22,6 +22,95 @@
|
||||
*/
|
||||
|
||||
#include "dpb_buffer_manager.h"
|
||||
#include "frontend/winsys_handle.h"
|
||||
#include "vl/vl_video_buffer.h"
|
||||
#include "gallium/drivers/d3d12/d3d12_interop_public.h"
|
||||
|
||||
HRESULT
|
||||
dpb_buffer_manager::get_read_only_handle(struct pipe_video_buffer *buffer,
|
||||
struct pipe_context *pipe,
|
||||
ComPtr<ID3D12Device>& device,
|
||||
HANDLE *pReadOnlyHandle,
|
||||
UINT* pSubresourceIndex)
|
||||
{
|
||||
if (!buffer || !pipe || !device || !pReadOnlyHandle || !pSubresourceIndex)
|
||||
return E_POINTER;
|
||||
|
||||
*pReadOnlyHandle = nullptr;
|
||||
|
||||
// Get pipe resources from the video buffer
|
||||
struct pipe_resource *buf_resources[VL_NUM_COMPONENTS];
|
||||
memset(buf_resources, 0, sizeof(buf_resources));
|
||||
buffer->get_resources(buffer, &buf_resources[0]);
|
||||
|
||||
if (!buf_resources[0])
|
||||
return E_INVALIDARG;
|
||||
|
||||
// Get the winsys handle for the resource
|
||||
struct winsys_handle src_wshandle = {};
|
||||
src_wshandle.type = WINSYS_HANDLE_TYPE_D3D12_RES;
|
||||
|
||||
if (!pipe->screen->resource_get_handle(pipe->screen,
|
||||
pipe,
|
||||
buf_resources[0],
|
||||
&src_wshandle,
|
||||
0 /*usage*/))
|
||||
{
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
if (!src_wshandle.com_obj)
|
||||
return E_FAIL;
|
||||
|
||||
// Create a read-only shared handle from the D3D12 resource
|
||||
HRESULT hr = S_OK;
|
||||
HANDLE originalHandle = nullptr;
|
||||
|
||||
// First, create a shared handle with full access from the original resource
|
||||
hr = device->CreateSharedHandle(static_cast<ID3D12Resource*>(src_wshandle.com_obj),
|
||||
nullptr, // Security attributes (default)
|
||||
GENERIC_ALL, // Full access for the original handle
|
||||
nullptr, // Name
|
||||
&originalHandle);
|
||||
if (FAILED(hr) || !originalHandle)
|
||||
return hr;
|
||||
|
||||
// Duplicate the handle with restricted (read-only) access rights
|
||||
// This creates a new handle that can only be used for reading
|
||||
BOOL duplicateResult = DuplicateHandle(
|
||||
GetCurrentProcess(), // Source process handle
|
||||
originalHandle, // Source handle
|
||||
GetCurrentProcess(), // Target process handle
|
||||
pReadOnlyHandle, // Target handle
|
||||
GENERIC_READ, // Desired access (read-only)
|
||||
FALSE, // Inherit handle
|
||||
0); // Options
|
||||
|
||||
// Clean up the original handle since we only need the read-only version
|
||||
CloseHandle(originalHandle);
|
||||
|
||||
if (!duplicateResult || !*pReadOnlyHandle)
|
||||
{
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
}
|
||||
|
||||
// Retrieve subresource index if available
|
||||
// from the associated data of the video buffer
|
||||
// which will contain the subresource index
|
||||
// if the underlying resource uses texture arrays
|
||||
if (buffer->associated_data)
|
||||
{
|
||||
struct d3d12_interop_video_buffer_associated_data* associated_data =
|
||||
static_cast<struct d3d12_interop_video_buffer_associated_data*>(buffer->associated_data);
|
||||
*pSubresourceIndex = associated_data->subresource_index;
|
||||
}
|
||||
else
|
||||
{
|
||||
*pSubresourceIndex = 0; // Default to 0 if no associated data
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// retrieve a buffer from the pool
|
||||
struct pipe_video_buffer *
|
||||
@@ -62,6 +151,14 @@ dpb_buffer_manager::dpb_buffer_manager(
|
||||
m_template.height = height;
|
||||
m_template.buffer_format = buffer_format;
|
||||
|
||||
if (codec->context->screen->get_video_param( codec->context->screen,
|
||||
codec->profile,
|
||||
PIPE_VIDEO_ENTRYPOINT_ENCODE,
|
||||
PIPE_VIDEO_CAP_ENC_READABLE_RECONSTRUCTED_PICTURE ) != 0)
|
||||
{
|
||||
m_template.bind = PIPE_BIND_SHARED; // Indicate we want shared resource capabilities
|
||||
}
|
||||
|
||||
for( auto &entry : m_pool )
|
||||
entry.buffer = m_codec->create_dpb_buffer( m_codec, NULL, &m_template );
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "pipe_headers.h"
|
||||
#include "hmft_entrypoints.h"
|
||||
|
||||
class dpb_buffer_manager
|
||||
{
|
||||
@@ -39,6 +39,15 @@ class dpb_buffer_manager
|
||||
// release a buffer back to the pool
|
||||
void release_dpb_buffer( struct pipe_video_buffer *target );
|
||||
|
||||
/**
|
||||
* get a read-only shared handle from the video buffer's internal D3D12 resource
|
||||
*/
|
||||
static HRESULT get_read_only_handle(struct pipe_video_buffer *buffer,
|
||||
struct pipe_context *pipe,
|
||||
ComPtr<ID3D12Device>& device,
|
||||
HANDLE *pReadOnlyHandle,
|
||||
UINT* pSubresourceIndex);
|
||||
|
||||
private:
|
||||
struct pipe_video_codec *m_codec = NULL;
|
||||
struct pipe_video_buffer m_template = {};
|
||||
|
||||
@@ -538,6 +538,33 @@ CDX12EncHMFT::PrepareForEncode( IMFSample *pSample, LPDX12EncodeContext *ppDX12E
|
||||
pDX12EncodeContext->encoderPicInfo.base.in_fence_value = pipeEncoderInputFenceHandleValue;
|
||||
CHECKHR_GOTO( PrepareForEncodeHelper( pDX12EncodeContext, bReceivedDirtyRectBlob, dirtyRectFrameNum ), done );
|
||||
|
||||
// Needs to be run after PrepareForEncodeHelper to know if current frame is used as reference
|
||||
// Only allocate reconstructed picture copy buffer if feature is enabled and supported
|
||||
if( (m_VideoReconstructedPictureMode == RECON_PIC_OUTPUT_MODE_BLIT_COPY) &&
|
||||
m_EncoderCapabilities.m_bHWSupportReadableReconstructedPicture)
|
||||
{
|
||||
if( !m_spReconstructedPictureBufferPool )
|
||||
{
|
||||
CHECKHR_GOTO( stats_buffer_manager::Create( m_pVlScreen,
|
||||
m_pPipeContext,
|
||||
MFSampleExtension_VideoEncodeReconstructedPicture,
|
||||
pDX12EncodeContext->pPipeVideoBuffer->width,
|
||||
static_cast<uint16_t>( pDX12EncodeContext->pPipeVideoBuffer->height ),
|
||||
pDX12EncodeContext->pPipeVideoBuffer->buffer_format,
|
||||
( m_bLowLatency ? MFT_STAT_POOL_MIN_SIZE : MFT_INPUT_QUEUE_DEPTH ),
|
||||
m_spReconstructedPictureBufferPool.GetAddressOf() ),
|
||||
done );
|
||||
}
|
||||
|
||||
// Only allocate the reconstructed picture copy buffer if the current frame is used as reference
|
||||
if (pDX12EncodeContext->get_current_dpb_pic_resource() != nullptr)
|
||||
{
|
||||
pDX12EncodeContext->pPipeResourceReconstructedPicture = m_spReconstructedPictureBufferPool->get_new_tracked_buffer();
|
||||
pDX12EncodeContext->PipeResourceReconstructedPictureSubresource = 0;
|
||||
CHECKNULL_GOTO( pDX12EncodeContext->pPipeResourceReconstructedPicture, E_OUTOFMEMORY, done );
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
struct pipe_resource templ = {};
|
||||
|
||||
|
||||
@@ -388,6 +388,32 @@ DEFINE_GUID( MFSampleExtension_VideoEncodeSatdMap, 0xadf61d96, 0xc2d3, 0x4b57, 0
|
||||
|
||||
#endif
|
||||
|
||||
// MFSampleExtension_VideoEncodeReconstructedPicture {3E8A1B7F-5C92-4D6E-B834-F0A729E65C48}
|
||||
// Type: IMFMediaBuffer
|
||||
// The reconstructed picture data of an encoded video frame (Experimental).
|
||||
DEFINE_GUID( MFSampleExtension_VideoEncodeReconstructedPicture, 0x3e8a1b7f, 0x5c92, 0x4d6e, 0xb8, 0x34, 0xf0, 0xa7, 0x29, 0xe6, 0x5c, 0x48 );
|
||||
|
||||
#ifndef CODECAPI_AVEncVideoReconstructedPictureOutputMode
|
||||
// AVEncVideoReconstructedPictureOutputMode (VT_UI4) (Experimental, Testing only)
|
||||
// Specifies the reconstructed picture output mode for video encoding.
|
||||
// 0: disable; 1: blit copy; 2: read-only shared resource
|
||||
DEFINE_CODECAPI_GUID( AVEncVideoReconstructedPictureOutputMode,
|
||||
"4A7B2E8F-1D93-4C6A-B548-91E2F8C5A7D3",
|
||||
0x4a7b2e8f,
|
||||
0x1d93,
|
||||
0x4c6a,
|
||||
0xb5,
|
||||
0x48,
|
||||
0x91,
|
||||
0xe2,
|
||||
0xf8,
|
||||
0xc5,
|
||||
0xa7,
|
||||
0xd3 )
|
||||
#define CODECAPI_AVEncVideoReconstructedPictureOutputMode DEFINE_CODECAPI_GUIDNAMED( AVEncVideoReconstructedPictureOutputMode )
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef CODECAPI_AVEncVideoInputDeltaQPBlockSettings
|
||||
// AVEncVideoInputDeltaQPSettings (VT_BLOB)
|
||||
// Read-only parameter that specifies the settings that the encoder MFT supports with respect to delta QP values as input.
|
||||
@@ -619,6 +645,10 @@ class __declspec( uuid( HMFT_GUID ) ) CDX12EncHMFT : CMFD3DManager,
|
||||
pipe_resource *pPipeResourceSATDMapStats,
|
||||
ComPtr<ID3D12Fence> &pResolveStatsCompletionFence,
|
||||
UINT64 ResolveStatsCompletionFenceValue,
|
||||
pipe_resource *pPipeResourceReconstructedPicture,
|
||||
UINT PipeResourceReconstructedPictureSubresource,
|
||||
ComPtr<ID3D12Fence>& spReconstructedPictureCompletionFence,
|
||||
UINT64 ReconstructedPictureCompletionFenceValue,
|
||||
ID3D12CommandQueue *pSyncObjectQueue );
|
||||
void GetSliceBitstreamMetadata( LPDX12EncodeContext pDX12EncodeContext, uint32_t slice_idx, std::vector<struct codec_unit_location_t> &codec_unit_metadata );
|
||||
void ProcessSliceBitstreamZeroCopy( LPDX12EncodeContext pDX12EncodeContext,
|
||||
@@ -633,6 +663,7 @@ class __declspec( uuid( HMFT_GUID ) ) CDX12EncHMFT : CMFD3DManager,
|
||||
DWORD dwReceivedInput,
|
||||
BOOL bIsLastSlice,
|
||||
uint64_t ResolveStatsCompletionFenceValue );
|
||||
|
||||
HRESULT UpdateAvailableInputType();
|
||||
HRESULT InternalCheckInputType( IMFMediaType *pType );
|
||||
HRESULT InternalCheckOutputType( IMFMediaType *pType );
|
||||
@@ -770,6 +801,15 @@ class __declspec( uuid( HMFT_GUID ) ) CDX12EncHMFT : CMFD3DManager,
|
||||
UINT32 m_uiVideoOutputBitsUsedMapBlockSize = 0;
|
||||
UINT32 m_uiVideoSatdMapBlockSize = 0;
|
||||
|
||||
typedef enum RECON_PIC_OUTPUT_MODE
|
||||
{
|
||||
RECON_PIC_OUTPUT_MODE_DISABLED = 0,
|
||||
RECON_PIC_OUTPUT_MODE_BLIT_COPY = 1,
|
||||
RECON_PIC_OUTPUT_MODE_READ_ONLY_SHARED_RESOURCE = 2,
|
||||
} RECON_PIC_OUTPUT_MODE;
|
||||
|
||||
RECON_PIC_OUTPUT_MODE m_VideoReconstructedPictureMode = RECON_PIC_OUTPUT_MODE_DISABLED;
|
||||
|
||||
UINT32 m_uiSliceGenerationMode = 0;
|
||||
BOOL m_bSliceGenerationModeSet = FALSE;
|
||||
|
||||
|
||||
@@ -287,6 +287,7 @@ done:
|
||||
HRESULT
|
||||
MFAttachPipeResourceAsSampleExtension( struct pipe_context *pPipeContext,
|
||||
struct pipe_resource *pPipeRes,
|
||||
UINT PipeResourceReconstructedPictureSubresource,
|
||||
ID3D12CommandQueue *pSyncObjectQueue,
|
||||
REFGUID guidExtension,
|
||||
IMFSample *pSample )
|
||||
@@ -311,7 +312,7 @@ MFAttachPipeResourceAsSampleExtension( struct pipe_context *pPipeContext,
|
||||
|
||||
ID3D12Resource *pD3D12Res = static_cast<ID3D12Resource *>( whandle.com_obj );
|
||||
ComPtr<IMFMediaBuffer> spMediaBuffer;
|
||||
HRESULT hr = MFCreateDXGISurfaceBuffer( __uuidof( ID3D12Resource ), pD3D12Res, 0, FALSE, &spMediaBuffer );
|
||||
HRESULT hr = MFCreateDXGISurfaceBuffer( __uuidof( ID3D12Resource ), pD3D12Res, PipeResourceReconstructedPictureSubresource, FALSE, &spMediaBuffer );
|
||||
|
||||
if( FAILED( hr ) )
|
||||
{
|
||||
|
||||
@@ -51,6 +51,7 @@ MFCopySample( IMFSample *dest, IMFSample *src, IMFMediaType *pmt );
|
||||
HRESULT
|
||||
MFAttachPipeResourceAsSampleExtension( struct pipe_context *pPipeContext,
|
||||
struct pipe_resource *pPipeRes,
|
||||
UINT PipeResourceReconstructedPictureSubresource,
|
||||
ID3D12CommandQueue *pSyncObjectQueue,
|
||||
REFGUID guidExtension,
|
||||
IMFSample *pSample );
|
||||
|
||||
@@ -87,6 +87,11 @@ CMFD3DManager::Shutdown( bool bReleaseDeviceManager )
|
||||
m_spQPMapStatsBufferPool.Reset();
|
||||
}
|
||||
|
||||
if( m_spReconstructedPictureBufferPool )
|
||||
{
|
||||
m_spReconstructedPictureBufferPool.Reset();
|
||||
}
|
||||
|
||||
if( m_spDeviceManager != nullptr )
|
||||
{
|
||||
if( m_hDevice != NULL )
|
||||
@@ -327,8 +332,6 @@ CMFD3DManager::xOnSetD3DManager( ULONG_PTR ulParam )
|
||||
HRESULT hr = S_OK;
|
||||
Shutdown();
|
||||
|
||||
d3d12_interop_device_info1 screen_interop_info = {};
|
||||
|
||||
if( ulParam == 0 )
|
||||
{
|
||||
return hr;
|
||||
@@ -349,17 +352,18 @@ CMFD3DManager::xOnSetD3DManager( ULONG_PTR ulParam )
|
||||
MF_E_DXGI_DEVICE_NOT_INITIALIZED,
|
||||
done );
|
||||
|
||||
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 ) )
|
||||
m_pVlScreen->pscreen->interop_query_device_info( m_pVlScreen->pscreen,
|
||||
sizeof( d3d12_interop_device_info1 ),
|
||||
&m_ScreenInteropInfo );
|
||||
assert( m_ScreenInteropInfo.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,
|
||||
CHECKBOOL_GOTO( m_ScreenInteropInfo.set_context_queue_priority_manager( m_pPipeContext, &m_ContextPriorityMgr.base ) == 0,
|
||||
MF_E_DXGI_DEVICE_NOT_INITIALIZED,
|
||||
done );
|
||||
|
||||
|
||||
@@ -104,12 +104,14 @@ class CMFD3DManager
|
||||
ComPtr<stats_buffer_manager> m_spSatdStatsBufferPool;
|
||||
ComPtr<stats_buffer_manager> m_spBitsUsedStatsBufferPool;
|
||||
ComPtr<stats_buffer_manager> m_spQPMapStatsBufferPool;
|
||||
ComPtr<stats_buffer_manager> m_spReconstructedPictureBufferPool;
|
||||
|
||||
UINT32 m_uiResetToken = 0;
|
||||
HANDLE m_hDevice = NULL;
|
||||
struct vl_screen *m_pVlScreen = nullptr;
|
||||
struct sw_winsys *m_pWinsys = nullptr;
|
||||
struct pipe_context *m_pPipeContext = nullptr;
|
||||
struct d3d12_interop_device_info1 m_ScreenInteropInfo = {};
|
||||
|
||||
struct mft_context_queue_priority_manager m_ContextPriorityMgr = {};
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "mfpipeinterop.h"
|
||||
#include "wpptrace.h"
|
||||
#include "d3d12_suballoc_mediabuffer.h"
|
||||
#include "dpb_buffer_manager.h"
|
||||
|
||||
#include "mftransform.tmh"
|
||||
|
||||
@@ -569,6 +570,7 @@ CDX12EncHMFT::OnOutputTypeChanged()
|
||||
m_spSatdStatsBufferPool.Reset();
|
||||
m_spBitsUsedStatsBufferPool.Reset();
|
||||
m_spQPMapStatsBufferPool.Reset();
|
||||
m_spReconstructedPictureBufferPool.Reset();
|
||||
}
|
||||
|
||||
// Indicate that we'll be adding MF_NALU_LENGTH_INFORMATION on each output sample that comes
|
||||
@@ -926,29 +928,24 @@ CDX12EncHMFT::InitializeEncoder( pipe_video_profile videoProfile, UINT32 Width,
|
||||
#endif // ENCODE_WITH_TWO_PASS_LOWEST_RES
|
||||
|
||||
encoderSettings.two_pass.skip_1st_dpb_texture = m_bRateControlFramePreAnalysisExternalReconDownscale ? true : false;
|
||||
|
||||
if( encoderSettings.two_pass.enable && ( encoderSettings.two_pass.pow2_downscale_factor > 0 ) )
|
||||
{
|
||||
struct pipe_video_codec blitterSettings = {};
|
||||
blitterSettings.entrypoint = PIPE_VIDEO_ENTRYPOINT_PROCESSING;
|
||||
blitterSettings.width = Width;
|
||||
blitterSettings.height = Height;
|
||||
CHECKNULL_GOTO( m_pPipeVideoBlitter = m_pPipeContext->create_video_codec( m_pPipeContext, &blitterSettings ),
|
||||
MF_E_UNEXPECTED,
|
||||
done );
|
||||
}
|
||||
}
|
||||
|
||||
struct d3d12_interop_device_info1 screen_interop_info = {};
|
||||
if( ( m_pPipeContext->screen->interop_query_device_info( m_pPipeContext->screen,
|
||||
sizeof( d3d12_interop_device_info1 ),
|
||||
&screen_interop_info ) != 0 ) &&
|
||||
( screen_interop_info.set_video_encoder_max_async_queue_depth != nullptr ) )
|
||||
if( (encoderSettings.two_pass.enable && ( encoderSettings.two_pass.pow2_downscale_factor > 0 )) ||
|
||||
(m_VideoReconstructedPictureMode == RECON_PIC_OUTPUT_MODE_BLIT_COPY) )
|
||||
{
|
||||
screen_interop_info.set_video_encoder_max_async_queue_depth( m_pPipeContext,
|
||||
( m_bLowLatency ? 1 : MFT_INPUT_QUEUE_DEPTH ) );
|
||||
struct pipe_video_codec blitterSettings = {};
|
||||
blitterSettings.entrypoint = PIPE_VIDEO_ENTRYPOINT_PROCESSING;
|
||||
blitterSettings.width = Width;
|
||||
blitterSettings.height = Height;
|
||||
CHECKNULL_GOTO( m_pPipeVideoBlitter = m_pPipeContext->create_video_codec( m_pPipeContext, &blitterSettings ),
|
||||
MF_E_UNEXPECTED,
|
||||
done );
|
||||
}
|
||||
|
||||
assert( m_ScreenInteropInfo.set_video_encoder_max_async_queue_depth != nullptr );
|
||||
m_ScreenInteropInfo.set_video_encoder_max_async_queue_depth( m_pPipeContext,
|
||||
( m_bLowLatency ? 1 : MFT_INPUT_QUEUE_DEPTH ) );
|
||||
|
||||
CHECKNULL_GOTO( m_pPipeVideoCodec = m_pPipeContext->create_video_codec( m_pPipeContext, &encoderSettings ),
|
||||
MF_E_UNEXPECTED,
|
||||
done );
|
||||
@@ -1209,6 +1206,10 @@ CDX12EncHMFT::ConfigureAsyncStatsMetadataOutputSampleAttributes( IMFSample *pSam
|
||||
pipe_resource *pPipeResourceSATDMapStats,
|
||||
ComPtr<ID3D12Fence> &pResolveStatsCompletionFence,
|
||||
UINT64 ResolveStatsCompletionFenceValue,
|
||||
pipe_resource *pPipeResourceReconstructedPicture,
|
||||
UINT PipeResourceReconstructedPictureSubresource,
|
||||
ComPtr<ID3D12Fence>& spReconstructedPictureCompletionFence,
|
||||
UINT64 ReconstructedPictureCompletionFenceValue,
|
||||
ID3D12CommandQueue *pSyncObjectQueue )
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
@@ -1228,6 +1229,7 @@ CDX12EncHMFT::ConfigureAsyncStatsMetadataOutputSampleAttributes( IMFSample *pSam
|
||||
{
|
||||
CHECKHR_GOTO( MFAttachPipeResourceAsSampleExtension( m_pPipeContext,
|
||||
pPipeResourcePSNRStats,
|
||||
0 /*subresource*/,
|
||||
pSyncObjectQueue,
|
||||
MFSampleExtension_FramePsnrYuv,
|
||||
pSample ), done );
|
||||
@@ -1263,6 +1265,35 @@ CDX12EncHMFT::ConfigureAsyncStatsMetadataOutputSampleAttributes( IMFSample *pSam
|
||||
pSample ), done );
|
||||
}
|
||||
|
||||
// Conditionally attach reconstructed picture copy (d3d12resource), gated by the completion fence
|
||||
// of the recon picture copy operation if any
|
||||
if (pPipeResourceReconstructedPicture)
|
||||
{
|
||||
if (m_VideoReconstructedPictureMode == RECON_PIC_OUTPUT_MODE_READ_ONLY_SHARED_RESOURCE)
|
||||
{
|
||||
assert(pPipeResourceReconstructedPicture);
|
||||
assert(!spReconstructedPictureCompletionFence); // No fence in this mode
|
||||
|
||||
CHECKHR_GOTO( MFAttachPipeResourceAsSampleExtension( m_pPipeContext,
|
||||
pPipeResourceReconstructedPicture,
|
||||
PipeResourceReconstructedPictureSubresource,
|
||||
pSyncObjectQueue,
|
||||
MFSampleExtension_VideoEncodeReconstructedPicture,
|
||||
pSample ), done );
|
||||
}
|
||||
else if (m_VideoReconstructedPictureMode == RECON_PIC_OUTPUT_MODE_BLIT_COPY)
|
||||
{
|
||||
assert(PipeResourceReconstructedPictureSubresource == 0); // Only single subresource in the copy output texture
|
||||
assert(pPipeResourceReconstructedPicture);
|
||||
assert(spReconstructedPictureCompletionFence); // Copy completion fence must be valid in this mode
|
||||
pSyncObjectQueue->Wait( spReconstructedPictureCompletionFence.Get(), ReconstructedPictureCompletionFenceValue );
|
||||
CHECKHR_GOTO( m_spReconstructedPictureBufferPool->AttachPipeResourceAsSampleExtension(
|
||||
pPipeResourceReconstructedPicture,
|
||||
pSyncObjectQueue,
|
||||
pSample ), done );
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
return hr;
|
||||
}
|
||||
@@ -1340,6 +1371,10 @@ CDX12EncHMFT::FinalizeAndEmitOutputSample( LPDX12EncodeContext pDX12EncodeContex
|
||||
pDX12EncodeContext->pPipeResourceSATDMapStats,
|
||||
pDX12EncodeContext->spAsyncFence,
|
||||
ResolveStatsCompletionFenceValue,
|
||||
pDX12EncodeContext->pPipeResourceReconstructedPicture,
|
||||
pDX12EncodeContext->PipeResourceReconstructedPictureSubresource,
|
||||
pDX12EncodeContext->spReconstructedPictureCompletionFence,
|
||||
pDX12EncodeContext->ReconstructedPictureCompletionFenceValue,
|
||||
pDX12EncodeContext->pSyncObjectQueue ) ) )
|
||||
{
|
||||
MFE_ERROR( "[dx12 hmft 0x%p] ConfigureAsyncStatsMetadataOutputSampleAttributes failed", this );
|
||||
@@ -1777,6 +1812,17 @@ CDX12EncHMFT::xThreadProc( void *pCtx )
|
||||
pDX12EncodeContext->pAsyncFence = nullptr;
|
||||
pDX12EncodeContext->spAsyncFence.Reset();
|
||||
|
||||
// CPU wait and destroy reconstructed picture copy fence if not null
|
||||
if( pDX12EncodeContext->pPipeFenceReconstructedPictureCompletionFence )
|
||||
{
|
||||
HMFT_ETW_EVENT_START( "ReconstructedPictureFenceWait", pThis );
|
||||
ASSERTED int wait_res = pThis->m_pPipeVideoCodec->fence_wait( pThis->m_pPipeVideoCodec,
|
||||
pDX12EncodeContext->pPipeFenceReconstructedPictureCompletionFence,
|
||||
OS_TIMEOUT_INFINITE );
|
||||
HMFT_ETW_EVENT_STOP( "ReconstructedPictureFenceWait", pThis );
|
||||
assert( wait_res );
|
||||
}
|
||||
|
||||
HMFT_ETW_EVENT_STOP( "TimeToProcessOutput", pThis );
|
||||
delete pDX12EncodeContext;
|
||||
} // while try_pop
|
||||
@@ -2434,10 +2480,10 @@ CDX12EncHMFT::ProcessInput( DWORD dwInputStreamIndex, IMFSample *pSample, DWORD
|
||||
&pDX12EncodeContext->encoderPicInfo.base );
|
||||
HMFT_ETW_EVENT_STOP( "PipeEndFrame", this );
|
||||
|
||||
uint64_t fence_value = 0;
|
||||
uint64_t AsyncFenceValue = 0;
|
||||
HANDLE fence_handle = (HANDLE) m_pPipeContext->screen->fence_get_win32_handle( m_pPipeContext->screen,
|
||||
pDX12EncodeContext->pAsyncFence,
|
||||
&fence_value );
|
||||
&AsyncFenceValue );
|
||||
CHECKNULL_GOTO( fence_handle, E_FAIL, done );
|
||||
CHECKHR_GOTO( m_spDevice->OpenSharedHandle( fence_handle, IID_PPV_ARGS( pDX12EncodeContext->spAsyncFence.ReleaseAndGetAddressOf() ) ), done );
|
||||
CloseHandle( fence_handle );
|
||||
@@ -2451,6 +2497,127 @@ CDX12EncHMFT::ProcessInput( DWORD dwInputStreamIndex, IMFSample *pSample, DWORD
|
||||
HMFT_ETW_EVENT_START( "PipeFlush", this );
|
||||
m_pPipeVideoCodec->flush( m_pPipeVideoCodec );
|
||||
HMFT_ETW_EVENT_STOP( "PipeFlush", this );
|
||||
|
||||
// Handle reconstructed picture copy if enabled
|
||||
if( m_VideoReconstructedPictureMode != RECON_PIC_OUTPUT_MODE_DISABLED )
|
||||
{
|
||||
HMFT_ETW_EVENT_START( "ReconstructedPictureSubmit", this );
|
||||
|
||||
// Get last slice completion fence
|
||||
pipe_fence_handle *fence_to_wait = nullptr;
|
||||
uint64_t fence_value = 0;
|
||||
assert( m_ScreenInteropInfo.get_video_enc_last_slice_completion_fence );
|
||||
|
||||
m_ScreenInteropInfo.get_video_enc_last_slice_completion_fence(
|
||||
m_pPipeVideoCodec,
|
||||
pDX12EncodeContext->pAsyncCookie,
|
||||
&fence_to_wait );
|
||||
|
||||
if( fence_to_wait )
|
||||
{
|
||||
HANDLE fence_handle = (HANDLE) m_pPipeContext->screen->fence_get_win32_handle( m_pPipeContext->screen,
|
||||
fence_to_wait,
|
||||
&fence_value );
|
||||
if( fence_handle )
|
||||
CloseHandle( fence_handle );
|
||||
}
|
||||
|
||||
struct pipe_video_buffer *src_buffer = pDX12EncodeContext->get_current_dpb_pic_buffer();
|
||||
assert( src_buffer );
|
||||
|
||||
// TODO: Readonly flags for get handle
|
||||
|
||||
// We only support zero copy read only reconstructed picture in low latency mode
|
||||
// and guarantee the src_buffer won't be modified until the next ProcessInput.
|
||||
// While technically we could guarantee the recon pic buffer will not be reused/
|
||||
// or rewritten by longer, it gets complicated to track and manage with all possible
|
||||
// LTR/SVC/NumRef combinations, so we limit it to the next ProcessInput in LowLatency mode.
|
||||
if (m_VideoReconstructedPictureMode == RECON_PIC_OUTPUT_MODE_READ_ONLY_SHARED_RESOURCE)
|
||||
{
|
||||
// We only support this mode in low latency mode for lifetime management reasons
|
||||
if (!m_bLowLatency)
|
||||
{
|
||||
debug_printf("[dx12 hmft 0x%p] Zero copy read only reconstructed picture is ONLY supported in low latency mode\n", this);
|
||||
assert(m_bLowLatency);
|
||||
CHECKHR_GOTO(E_FAIL, done);
|
||||
}
|
||||
|
||||
// Get read-only handle directly from the video buffer
|
||||
HANDLE readOnlyHandle = nullptr;
|
||||
HRESULT hr = dpb_buffer_manager::get_read_only_handle(src_buffer,
|
||||
m_pPipeContext,
|
||||
m_spDevice,
|
||||
&readOnlyHandle,
|
||||
&pDX12EncodeContext->PipeResourceReconstructedPictureSubresource);
|
||||
CHECKHR_GOTO( hr, done );
|
||||
CHECKNULL_GOTO( readOnlyHandle, E_FAIL, done );
|
||||
if( !readOnlyHandle )
|
||||
debug_printf("[dx12 hmft 0x%p] Failed to get read-only handle from video buffer\n", this);
|
||||
|
||||
struct winsys_handle src_wshandle = {};
|
||||
src_wshandle.type = WINSYS_HANDLE_TYPE_FD;
|
||||
src_wshandle.handle = readOnlyHandle;
|
||||
|
||||
assert(src_wshandle.handle);
|
||||
if (!src_wshandle.handle) {
|
||||
debug_printf("[dx12 hmft 0x%p] Invalid handle for reconstructed picture resource\n", this);
|
||||
CHECKHR_GOTO(E_FAIL, done);
|
||||
}
|
||||
// Import the reconstructed picture resource from handle
|
||||
pDX12EncodeContext->pPipeResourceReconstructedPicture =
|
||||
m_pPipeContext->screen->resource_from_handle( m_pPipeContext->screen,
|
||||
NULL,
|
||||
&src_wshandle,
|
||||
0 /*usage*/ );
|
||||
assert( pDX12EncodeContext->pPipeResourceReconstructedPicture );
|
||||
if (!pDX12EncodeContext->pPipeResourceReconstructedPicture) {
|
||||
debug_printf("[dx12 hmft 0x%p] Failed to import reconstructed picture resource\n", this);
|
||||
CHECKHR_GOTO(E_FAIL, done);
|
||||
}
|
||||
CloseHandle( readOnlyHandle );
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(m_pPipeVideoBlitter);
|
||||
|
||||
struct winsys_handle whandle = {};
|
||||
whandle.type = WINSYS_HANDLE_TYPE_D3D12_RES;
|
||||
whandle.modifier = 2; // Expected by video_buffer_from_handle to place a pipe_resource in the pipe_video_buffer
|
||||
whandle.com_obj = (void *) pDX12EncodeContext->pPipeResourceReconstructedPicture;
|
||||
struct pipe_video_buffer *dst_buffer =
|
||||
m_pPipeContext->video_buffer_from_handle( m_pPipeContext, src_buffer, &whandle, 0 );
|
||||
assert( dst_buffer );
|
||||
pDX12EncodeContext->PipeResourceReconstructedPictureSubresource = 0;
|
||||
|
||||
struct pipe_vpp_desc vpblit_params = {};
|
||||
vpblit_params.base.in_fence = fence_to_wait;
|
||||
vpblit_params.base.in_fence_value = fence_value;
|
||||
vpblit_params.base.out_fence = &pDX12EncodeContext->pPipeFenceReconstructedPictureCompletionFence;
|
||||
vpblit_params.base.input_format = src_buffer->buffer_format;
|
||||
vpblit_params.base.output_format = dst_buffer->buffer_format;
|
||||
vpblit_params.src_region.x1 = src_buffer->width;
|
||||
vpblit_params.src_region.y1 = src_buffer->height;
|
||||
vpblit_params.dst_region.x1 = dst_buffer->width;
|
||||
vpblit_params.dst_region.y1 = dst_buffer->height;
|
||||
|
||||
m_pPipeVideoBlitter->begin_frame( m_pPipeVideoBlitter, dst_buffer, &vpblit_params.base );
|
||||
m_pPipeVideoBlitter->process_frame( m_pPipeVideoBlitter, src_buffer, &vpblit_params );
|
||||
m_pPipeVideoBlitter->end_frame( m_pPipeVideoBlitter, dst_buffer, &vpblit_params.base );
|
||||
m_pPipeVideoBlitter->flush( m_pPipeVideoBlitter );
|
||||
|
||||
// Get D3D12 fence handle for synchronization
|
||||
HANDLE fence_handle = (HANDLE) m_pPipeContext->screen->fence_get_win32_handle( m_pPipeContext->screen,
|
||||
pDX12EncodeContext->pPipeFenceReconstructedPictureCompletionFence,
|
||||
&pDX12EncodeContext->ReconstructedPictureCompletionFenceValue );
|
||||
if( fence_handle )
|
||||
{
|
||||
CHECKHR_GOTO( m_spDevice->OpenSharedHandle( fence_handle, IID_PPV_ARGS( pDX12EncodeContext->spReconstructedPictureCompletionFence.ReleaseAndGetAddressOf() ) ), done );
|
||||
CloseHandle( fence_handle );
|
||||
}
|
||||
}
|
||||
|
||||
HMFT_ETW_EVENT_STOP( "ReconstructedPictureSubmit", this );
|
||||
}
|
||||
}
|
||||
// Release the QP map buffer after encode_bitstream call returns.
|
||||
if( qpMapBuffer && qpSize != 0 && qpData != nullptr )
|
||||
|
||||
Reference in New Issue
Block a user