From: Rémi Bernon rbernon@codeweavers.com
--- dlls/mf/mf_private.h | 3 + dlls/mf/session.c | 17 +++++ dlls/mf/tests/topology.c | 24 ++++---- dlls/mf/topology_loader.c | 126 +++++++++++++++++++++++++++++++------- 4 files changed, 136 insertions(+), 34 deletions(-)
diff --git a/dlls/mf/mf_private.h b/dlls/mf/mf_private.h index 7d169c0711f..1f2ef17a8c9 100644 --- a/dlls/mf/mf_private.h +++ b/dlls/mf/mf_private.h @@ -122,5 +122,8 @@ extern HRESULT create_topology(TOPOID id, IMFTopology **topology); extern HRESULT topology_node_get_object(IMFTopologyNode *node, REFIID riid, void **obj); extern HRESULT topology_node_get_type_handler(IMFTopologyNode *node, DWORD stream, BOOL output, IMFMediaTypeHandler **handler); extern HRESULT topology_node_init_media_type(IMFTopologyNode *node, DWORD stream, BOOL output, IMFMediaType **type); +extern BOOL topology_node_is_d3d_aware(IMFTopologyNode *node); +extern HRESULT topology_node_set_device_manager(IMFTopologyNode *node, IUnknown *device_manager); +extern HRESULT stream_sink_get_device_manager(IMFStreamSink *stream_sink, IUnknown **device_manager);
extern HRESULT enum_audio_capture_sources(IMFAttributes *attributes, IMFActivate ***sources, UINT32 *ret_count); diff --git a/dlls/mf/session.c b/dlls/mf/session.c index dc9578ce86b..a43147910fb 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -1790,6 +1790,8 @@ static HRESULT session_append_node(struct media_session *session, IMFTopologyNod
if (SUCCEEDED(hr = session_add_media_sink(session, node, media_sink))) { + IUnknown *device_manager; + if (SUCCEEDED(session_get_stream_sink_type(topo_node->object.sink_stream, &media_type))) { if (SUCCEEDED(MFGetService(topo_node->object.object, &MR_VIDEO_ACCELERATION_SERVICE, @@ -1807,6 +1809,21 @@ static HRESULT session_append_node(struct media_session *session, IMFTopologyNod } IMFMediaType_Release(media_type); } + + if (SUCCEEDED(stream_sink_get_device_manager(topo_node->object.sink_stream, &device_manager))) + { + IMFTopologyNode *upstream; + DWORD output; + + if (SUCCEEDED(IMFTopologyNode_GetInput(topo_node->node, 0, &upstream, &output))) + { + if (topology_node_is_d3d_aware(upstream)) + topology_node_set_device_manager(upstream, device_manager); + IMFTopologyNode_Release(upstream); + } + + IUnknown_Release(device_manager); + } } IMFMediaSink_Release(media_sink);
diff --git a/dlls/mf/tests/topology.c b/dlls/mf/tests/topology.c index 7b820c8abfa..4b2e83d7ee4 100644 --- a/dlls/mf/tests/topology.c +++ b/dlls/mf/tests/topology.c @@ -3261,7 +3261,7 @@ static void test_topology_loader_d3d(void) ok(hr == S_OK, "got hr %#lx.\n", hr); ref = IMFTopology_GetNodeCount(full_topology, &count); ok(hr == S_OK, "got hr %#lx.\n", hr); - todo_wine ok(count == 2, "got count %u.\n", count); + ok(count == 2, "got count %u.\n", count); ref = IMFTopology_Release(full_topology); ok(ref == 0, "Release returned %ld\n", ref);
@@ -3277,7 +3277,7 @@ static void test_topology_loader_d3d(void) ok(hr == S_OK, "got hr %#lx.\n", hr); ref = IMFTopology_GetNodeCount(full_topology, &count); ok(hr == S_OK, "got hr %#lx.\n", hr); - todo_wine ok(count == 2, "got count %u.\n", count); + ok(count == 2, "got count %u.\n", count); ref = IMFTopology_Release(full_topology); ok(ref == 0, "Release returned %ld\n", ref);
@@ -3310,7 +3310,7 @@ static void test_topology_loader_d3d(void) ok(hr == S_OK, "got hr %#lx.\n", hr); ref = IMFTopology_GetNodeCount(full_topology, &count); ok(hr == S_OK, "got hr %#lx.\n", hr); - todo_wine ok(count == 6, "got count %u.\n", count); + ok(count == 6, "got count %u.\n", count); ref = IMFTopology_Release(full_topology); ok(ref == 0, "Release returned %ld\n", ref);
@@ -3446,7 +3446,7 @@ static void test_topology_loader_d3d9(MFTOPOLOGY_DXVA_MODE mode) ok(hr == S_OK, "got hr %#lx.\n", hr); ref = IMFTopology_GetNodeCount(full_topology, &count); ok(hr == S_OK, "got hr %#lx.\n", hr); - todo_wine ok(count == 6, "got count %u.\n", count); + ok(count == 6, "got count %u.\n", count); ref = IMFTopology_Release(full_topology); ok(ref == 0, "Release returned %ld\n", ref);
@@ -3459,7 +3459,7 @@ static void test_topology_loader_d3d9(MFTOPOLOGY_DXVA_MODE mode) ret = test_transform_got_d3d9_device_manager(transforms[2]); ok(!ret, "got d3d9 device manager\n"); ret = test_transform_got_d3d9_device_manager(transforms[3]); - todo_wine ok(!!ret, "got d3d9 device manager\n"); + ok(!!ret, "got d3d9 device manager\n"); }
/* copier is inserted before the sink if preceding node may allocate samples without a device manager */ @@ -3470,7 +3470,7 @@ static void test_topology_loader_d3d9(MFTOPOLOGY_DXVA_MODE mode) ref = IMFTopology_GetNodeCount(full_topology, &count); ok(hr == S_OK, "got hr %#lx.\n", hr); if (mode == MFTOPOLOGY_DXVA_NONE || mode == MFTOPOLOGY_DXVA_FULL) - todo_wine ok(count == 6, "got count %u.\n", count); + ok(count == 6, "got count %u.\n", count); else ok(count == 7, "got count %u.\n", count); ref = IMFTopology_Release(full_topology); @@ -3485,7 +3485,7 @@ static void test_topology_loader_d3d9(MFTOPOLOGY_DXVA_MODE mode) ret = test_transform_got_d3d9_device_manager(transforms[2]); ok(!ret, "got d3d9 device manager\n"); ret = test_transform_got_d3d9_device_manager(transforms[3]); - todo_wine ok(!!ret, "got d3d9 device manager\n"); + ok(!!ret, "got d3d9 device manager\n"); }
output_stream_info.dwFlags = MFT_OUTPUT_STREAM_PROVIDES_SAMPLES; @@ -3494,7 +3494,7 @@ static void test_topology_loader_d3d9(MFTOPOLOGY_DXVA_MODE mode) ref = IMFTopology_GetNodeCount(full_topology, &count); ok(hr == S_OK, "got hr %#lx.\n", hr); if (mode == MFTOPOLOGY_DXVA_NONE || mode == MFTOPOLOGY_DXVA_FULL) - todo_wine ok(count == 6, "got count %u.\n", count); + ok(count == 6, "got count %u.\n", count); else ok(count == 7, "got count %u.\n", count); ref = IMFTopology_Release(full_topology); @@ -3509,7 +3509,7 @@ static void test_topology_loader_d3d9(MFTOPOLOGY_DXVA_MODE mode) ret = test_transform_got_d3d9_device_manager(transforms[2]); ok(!ret, "got d3d9 device manager\n"); ret = test_transform_got_d3d9_device_manager(transforms[3]); - todo_wine ok(!!ret, "got d3d9 device manager\n"); + ok(!!ret, "got d3d9 device manager\n"); }
ref = IMFTopology_Release(topology); @@ -3664,7 +3664,7 @@ static void test_topology_loader_d3d11(MFTOPOLOGY_DXVA_MODE mode) if (mode == MFTOPOLOGY_DXVA_NONE) ok(count == 6, "got count %u.\n", count); else - todo_wine ok(count == 7, "got count %u.\n", count); + todo_wine_if(mode == MFTOPOLOGY_DXVA_FULL) ok(count == 7, "got count %u.\n", count); ref = IMFTopology_Release(full_topology); ok(ref == 0, "Release returned %ld\n", ref);
@@ -3732,9 +3732,9 @@ static void test_topology_loader_d3d11(MFTOPOLOGY_DXVA_MODE mode) ret = test_transform_got_dxgi_device_manager(transforms[1]); ok(!ret, "got dxgi device manager\n"); ret = test_transform_got_dxgi_device_manager(transforms[2]); - todo_wine ok(!!ret, "got dxgi device manager\n"); + ok(!!ret, "got dxgi device manager\n"); ret = test_transform_got_dxgi_device_manager(transforms[3]); - todo_wine ok(!!ret, "got dxgi device manager\n"); + ok(!!ret, "got dxgi device manager\n"); }
ref = IMFTopology_Release(topology); diff --git a/dlls/mf/topology_loader.c b/dlls/mf/topology_loader.c index 96ae74dbfe2..f0fc2060bc0 100644 --- a/dlls/mf/topology_loader.c +++ b/dlls/mf/topology_loader.c @@ -24,6 +24,9 @@ #include "winbase.h"
#include "mfidl.h" +#include "evr.h" +#include "d3d9.h" +#include "dxva2api.h"
#include "wine/debug.h" #include "wine/list.h" @@ -564,25 +567,35 @@ static HRESULT topology_loader_resolve_branches(struct topoloader_context *conte return hr; }
-static BOOL topology_loader_is_node_d3d_aware(IMFTopologyNode *node) +static BOOL topology_node_get_object_attributes(IMFTopologyNode *node, IMFAttributes **attributes) { - IMFAttributes *attributes; - unsigned int d3d_aware = 0; IMFTransform *transform; + HRESULT hr;
- if (FAILED(topology_node_get_object(node, &IID_IMFAttributes, (void **)&attributes))) - return FALSE; - - IMFAttributes_GetUINT32(attributes, &MF_SA_D3D_AWARE, &d3d_aware); - IMFAttributes_Release(attributes); - - if (!d3d_aware && SUCCEEDED(topology_node_get_object(node, &IID_IMFTransform, (void **)&transform))) + if (SUCCEEDED(topology_node_get_object(node, &IID_IMFTransform, (void **)&transform))) { - d3d_aware = mf_is_sample_copier_transform(transform); + hr = IMFTransform_GetAttributes(transform, attributes); IMFTransform_Release(transform); + return hr; }
- return !!d3d_aware; + return topology_node_get_object(node, &IID_IMFAttributes, (void **)&attributes); +} + +BOOL topology_node_is_d3d_aware(IMFTopologyNode *node) +{ + UINT32 d3d_aware, d3d11_aware; + IMFAttributes *attributes; + + if (FAILED(topology_node_get_object_attributes(node, &attributes))) + return FALSE; + if (FAILED(IMFAttributes_GetUINT32(attributes, &MF_SA_D3D_AWARE, &d3d_aware))) + d3d_aware = FALSE; + if (FAILED(IMFAttributes_GetUINT32(attributes, &MF_SA_D3D11_AWARE, &d3d11_aware))) + d3d11_aware = FALSE; + IMFAttributes_Release(attributes); + + return d3d_aware || d3d11_aware; }
static HRESULT topology_loader_create_copier(IMFTopologyNode *upstream_node, DWORD upstream_output, @@ -638,33 +651,98 @@ static HRESULT topology_loader_connect_copier(struct topoloader_context *context return S_OK; }
+HRESULT topology_node_set_device_manager(IMFTopologyNode *node, IUnknown *device_manager) +{ + IMFTransform *transform; + HRESULT hr; + + if (SUCCEEDED(hr = topology_node_get_object(node, &IID_IMFTransform, (void **)&transform))) + { + hr = IMFTransform_ProcessMessage(transform, MFT_MESSAGE_SET_D3D_MANAGER, (LONG_PTR)device_manager); + IMFTransform_Release(transform); + } + + if (SUCCEEDED(hr)) + { + IMFTopologyNode *upstream; + DWORD i, count, output; + + hr = IMFTopologyNode_GetInputCount(node, &count); + + for (i = 0; SUCCEEDED(hr) && i < count; i++) + { + if (FAILED(IMFTopologyNode_GetInput(node, 0, &upstream, &output))) + continue; + + if (topology_node_is_d3d_aware(upstream)) + topology_node_set_device_manager(upstream, device_manager); + + IMFTopologyNode_Release(upstream); + } + } + + return hr; +} + +HRESULT stream_sink_get_device_manager(IMFStreamSink *stream_sink, IUnknown **device_manager) +{ + HRESULT hr; + + if (SUCCEEDED(hr = MFGetService((IUnknown *)stream_sink, &MR_VIDEO_ACCELERATION_SERVICE, + &IID_IMFDXGIDeviceManager, (void **)device_manager))) + return hr; + if (SUCCEEDED(hr = MFGetService((IUnknown *)stream_sink, &MR_VIDEO_ACCELERATION_SERVICE, + &IID_IDirect3DDeviceManager9, (void **)device_manager))) + return hr; + + return hr; +} + /* Right now this should be used for output nodes only. */ -static HRESULT topology_loader_connect_d3d_aware_input(struct topoloader_context *context, - IMFTopologyNode *node) +static HRESULT topology_loader_connect_d3d_aware_sink(struct topoloader_context *context, + IMFTopologyNode *node, MFTOPOLOGY_DXVA_MODE dxva_mode) { IMFTopologyNode *upstream_node; IMFTransform *copier = NULL; IMFStreamSink *stream_sink; + IUnknown *device_manager; DWORD upstream_output; HRESULT hr;
if (FAILED(hr = topology_node_get_object(node, &IID_IMFStreamSink, (void **)&stream_sink))) return hr;
- if (topology_loader_is_node_d3d_aware(node)) + if (SUCCEEDED(hr = stream_sink_get_device_manager(stream_sink, &device_manager))) { if (SUCCEEDED(IMFTopologyNode_GetInput(node, 0, &upstream_node, &upstream_output))) { - if (!topology_loader_is_node_d3d_aware(upstream_node)) + BOOL needs_copier = dxva_mode == MFTOPOLOGY_DXVA_DEFAULT; + IMFTransform *transform; + + if (needs_copier && SUCCEEDED(topology_node_get_object(upstream_node, &IID_IMFTransform, (void **)&transform))) { - if (SUCCEEDED(hr = topology_loader_create_copier(upstream_node, upstream_output, node, 0, &copier))) - { - hr = topology_loader_connect_copier(context, upstream_node, upstream_output, node, 0, copier); - IMFTransform_Release(copier); - } + MFT_OUTPUT_STREAM_INFO info = {0}; + + if (FAILED(IMFTransform_GetOutputStreamInfo(transform, upstream_output, &info)) + || !(info.dwFlags & (MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES | MFT_OUTPUT_STREAM_PROVIDES_SAMPLES))) + needs_copier = FALSE; + + IMFTransform_Release(transform); } + + if (needs_copier && SUCCEEDED(hr = topology_loader_create_copier(upstream_node, upstream_output, node, 0, &copier))) + { + hr = topology_loader_connect_copier(context, upstream_node, upstream_output, node, 0, copier); + IMFTransform_Release(copier); + } + + if (dxva_mode == MFTOPOLOGY_DXVA_FULL && topology_node_is_d3d_aware(upstream_node)) + topology_node_set_device_manager(upstream_node, device_manager); + IMFTopologyNode_Release(upstream_node); } + + IUnknown_Release(device_manager); }
IMFStreamSink_Release(stream_sink); @@ -674,6 +752,7 @@ static HRESULT topology_loader_connect_d3d_aware_input(struct topoloader_context
static void topology_loader_resolve_complete(struct topoloader_context *context) { + MFTOPOLOGY_DXVA_MODE dxva_mode; MF_TOPOLOGY_TYPE node_type; IMFTopologyNode *node; WORD i, node_count; @@ -681,6 +760,9 @@ static void topology_loader_resolve_complete(struct topoloader_context *context)
IMFTopology_GetNodeCount(context->output_topology, &node_count);
+ if (FAILED(IMFTopology_GetUINT32(context->input_topology, &MF_TOPOLOGY_DXVA_MODE, (UINT32 *)&dxva_mode))) + dxva_mode = 0; + for (i = 0; i < node_count; ++i) { if (SUCCEEDED(IMFTopology_GetNode(context->output_topology, i, &node))) @@ -693,7 +775,7 @@ static void topology_loader_resolve_complete(struct topoloader_context *context) if (FAILED(IMFTopologyNode_GetItem(node, &MF_TOPONODE_STREAMID, NULL))) IMFTopologyNode_SetUINT32(node, &MF_TOPONODE_STREAMID, 0);
- if (FAILED(hr = topology_loader_connect_d3d_aware_input(context, node))) + if (FAILED(hr = topology_loader_connect_d3d_aware_sink(context, node, dxva_mode))) WARN("Failed to connect D3D-aware input, hr %#lx.\n", hr); } else if (node_type == MF_TOPOLOGY_SOURCESTREAM_NODE)
Nikolay Sivov (@nsivov) commented about dlls/mf/topology_loader.c:
IMFTopology_GetNodeCount(context->output_topology, &node_count);
- if (FAILED(IMFTopology_GetUINT32(context->input_topology, &MF_TOPOLOGY_DXVA_MODE, (UINT32 *)&dxva_mode)))
dxva_mode = 0;
Have you checked if this attribute applies to d3d11 device manager as well, and not only for d3d9?
On Mon Jul 1 07:15:45 2024 +0000, Nikolay Sivov wrote:
Have you checked if this attribute applies to d3d11 device manager as well, and not only for d3d9?
The tests (`test_topology_loader_d3d11`) cover that? There's one difference between d3d9 and d3d11 with how `MFTOPOLOGY_DXVA_FULL` / `MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES` are behaving: d3d11 inserts a copier in case a transform *can* allocate sample without a device manager while d3d9 doesn't. I chose to follow d3d9 behavior here, and avoid an unnecessary copier.
I don't think we have that behavior anywhere anyway, MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES isn't used in our transforms, and not necessarily a sign that the transform will allocate its own samples, but native probably takes the safest path.
This merge request was approved by Nikolay Sivov.