mediafoundation: Move dpb_buffer_manager::get_read_only_handle into d3d12 driver and cache resource

Reviewed-by: Pohsiang (John) Hsu <pohhsu@microsoft.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/38750>
This commit is contained in:
Silvio Vilerino 2025-11-24 09:27:42 -05:00 committed by Marge Bot
parent 16c98f4f18
commit 3917a5d12a
6 changed files with 135 additions and 125 deletions

View file

@ -33,17 +33,19 @@ extern "C" {
struct ID3D12Device;
struct ID3D12CommandQueue;
struct ID3D12Resource;
struct pipe_video_buffer;
struct pipe_context;
struct pipe_resource;
struct d3d12_interop_video_buffer_associated_data
{
/*
* Subresource index within the underlying ID3D12Resource
* representing this video buffer.
*
* This is useful when the underlying resource is a texture array
* and each video buffer maps to a different subresource within it.
* Function to get read-only resource from video buffer.
*/
uint32_t subresource_index;
bool (*get_read_only_resource)(struct pipe_video_buffer *buffer,
struct pipe_context *pipe,
struct pipe_resource **readonly_resource,
uint32_t *subresource_index);
};
struct d3d12_interop_device_info {

View file

@ -39,6 +39,111 @@
#include "d3d12_format.h"
#include "d3d12_screen.h"
#ifdef _WIN32
static bool
d3d12_video_buffer_get_read_only_resource(struct pipe_video_buffer *buffer,
struct pipe_context *pipe,
struct pipe_resource **pReadOnlyResource,
uint32_t *pSubresourceIndex)
{
if( !buffer || !pipe || !pReadOnlyResource || !pSubresourceIndex )
return false;
*pReadOnlyResource = nullptr;
*pSubresourceIndex = 0;
struct d3d12_video_buffer *d3d12_buf = (struct d3d12_video_buffer *) buffer;
// If we have already created a read-only resource for this buffer, reuse it
if (d3d12_buf->readonly_resource)
{
*pReadOnlyResource = (struct pipe_resource *) d3d12_buf->readonly_resource;
*pSubresourceIndex = d3d12_buf->subresource_index;
return true;
}
// 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 false;
// 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*/ ) ||
!src_wshandle.com_obj )
{
return false;
}
// Create a read-only shared handle from the D3D12 resource
HANDLE originalHandle = nullptr;
// First, create a shared handle with full access from the original resource
struct d3d12_screen *screen = (struct d3d12_screen *) pipe->screen;
HRESULT hr = screen->dev->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 ) )
return false;
// Duplicate the handle with restricted (read-only) access rights
// This creates a new handle that can only be used for reading
assert(originalHandle);
src_wshandle = {};
src_wshandle.type = WINSYS_HANDLE_TYPE_FD;
BOOL duplicateResult = DuplicateHandle( GetCurrentProcess(), // Source process handle
originalHandle, // Source handle
GetCurrentProcess(), // Target process handle
&src_wshandle.handle, // 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 );
assert( src_wshandle.handle );
if( !duplicateResult || !src_wshandle.handle )
{
debug_printf( "[d3d12_video_buffer_get_read_only_resource] Invalid handle for reconstructed picture resource\n" );
return false;
}
// Create a winsys handle for the read-only resource
// and import it back as a pipe_resource
*pReadOnlyResource = pipe->screen->resource_from_handle( pipe->screen, NULL, &src_wshandle, 0 /*usage*/ );
CloseHandle( src_wshandle.handle ); // Close our local copy of the handle after import
if( !*pReadOnlyResource )
{
assert( *pReadOnlyResource );
debug_printf( "[d3d12_video_buffer_get_read_only_resource] Failed to import reconstructed picture resource\n" );
return false;
}
// Cache the resource for future use
// The d3d12_video_buffer manages the lifetime of this resource
// and the app is given a weak reference to it via pReadOnlyResource
// The cached resource will be destroyed when the video buffer is destroyed
d3d12_buf->readonly_resource = (void*) *pReadOnlyResource;
// Return the subresource index
// from the video buffer which will contain the subresource index
// if the underlying resource uses texture arrays
*pSubresourceIndex = d3d12_buf->subresource_index;
return true;
}
#endif // _WIN32
static struct pipe_video_buffer *
d3d12_video_buffer_create_impl(struct pipe_context *pipe,
const struct pipe_video_buffer *tmpl,
@ -66,6 +171,9 @@ d3d12_video_buffer_create_impl(struct pipe_context *pipe,
pD3D12VideoBuffer->base.interlaced = tmpl->interlaced;
pD3D12VideoBuffer->base.contiguous_planes = true;
pD3D12VideoBuffer->base.associated_data = &pD3D12VideoBuffer->d3d12_video_buffer_associated_data;
#ifdef _WIN32
pD3D12VideoBuffer->d3d12_video_buffer_associated_data.get_read_only_resource = d3d12_video_buffer_get_read_only_resource;
#endif // _WIN32
pD3D12VideoBuffer->idx_texarray_slots = 0;
pD3D12VideoBuffer->m_spVideoTexArrayDPBPoolInUse.reset();
@ -253,6 +361,11 @@ d3d12_video_buffer_destroy(struct pipe_video_buffer *buffer)
}
}
// Clean up readonly_resource
if (pD3D12VideoBuffer->readonly_resource) {
pipe_resource_reference((struct pipe_resource**)&pD3D12VideoBuffer->readonly_resource, NULL);
}
delete pD3D12VideoBuffer;
}
@ -535,7 +648,7 @@ d3d12_video_create_dpb_buffer_texarray(struct pipe_video_codec *codec,
if (((*pD3D12Enc->m_spVideoTexArrayDPBPoolInUse) & (1 << i)) == 0)
{
buf->idx_texarray_slots = i;
buf->d3d12_video_buffer_associated_data.subresource_index = i;
buf->subresource_index = i;
(*pD3D12Enc->m_spVideoTexArrayDPBPoolInUse) |= (1 << buf->idx_texarray_slots); // Mark i-th bit as used
bFoundEmptySlot = true;
break;

View file

@ -109,6 +109,9 @@ struct d3d12_video_buffer
// Points to the same address as d3d12_video_encoder::m_spVideoTexArrayDPBPoolInUse
std::shared_ptr<uint32_t> m_spVideoTexArrayDPBPoolInUse;
struct d3d12_interop_video_buffer_associated_data d3d12_video_buffer_associated_data = {};
uint32_t subresource_index = 0;
void* readonly_resource = nullptr;
};
///

View file

@ -31,86 +31,6 @@
#include "dpb_buffer_manager.tmh"
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 *

View file

@ -44,14 +44,6 @@ 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:
const void *m_logId = {};

View file

@ -28,6 +28,7 @@
#include "mfbufferhelp.h"
#include "mfpipeinterop.h"
#include "wpptrace.h"
#include "gallium/drivers/d3d12/d3d12_interop_public.h"
#include "mftransform.tmh"
@ -2574,38 +2575,17 @@ CDX12EncHMFT::ProcessInput( DWORD dwInputStreamIndex, IMFSample *pSample, DWORD
}
// 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 )
struct d3d12_interop_video_buffer_associated_data *associated_data =
static_cast<struct d3d12_interop_video_buffer_associated_data *>( src_buffer->associated_data );
if(associated_data->get_read_only_resource &&
(!associated_data->get_read_only_resource( src_buffer,
m_pPipeContext,
&pDX12EncodeContext->pPipeResourceReconstructedPicture,
&pDX12EncodeContext->PipeResourceReconstructedPictureSubresource ) || !pDX12EncodeContext->pPipeResourceReconstructedPicture) )
{
debug_printf( "[dx12 hmft 0x%p] Invalid handle for reconstructed picture resource\n", this );
CHECKHR_GOTO( E_FAIL, done );
debug_printf( "[dx12 hmft 0x%p] Failed to get read-only resource from reference video buffer\n", this );
}
// 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 );
CHECKNULL_GOTO( pDX12EncodeContext->pPipeResourceReconstructedPicture, E_FAIL, done );
}
else
{