[PATCH v5 0/3] MR5464: mf/tests: Check that D3D aware attribute has no effect on the topology.
Wine incorrectly inserts a sample copier. D3D awareness is handled per node, and each node will have their own sample allocator created from the D3D device manager provided by the session. -- v5: mf/tests: Test device manager handling in the topology loader. mf/tests: Test D3D awareness handling in the topology loader. include: Add MFTOPOLOGY_DXVA_MODE enum definition. https://gitlab.winehq.org/wine/wine/-/merge_requests/5464
From: Rémi Bernon <rbernon(a)codeweavers.com> --- include/mfidl.idl | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/include/mfidl.idl b/include/mfidl.idl index b3201b12d84..666af53c6e3 100644 --- a/include/mfidl.idl +++ b/include/mfidl.idl @@ -131,6 +131,13 @@ typedef enum _MF_VIDEO_PROCESSOR_ALGORITHM_TYPE MF_VIDEO_PROCESSOR_ALGORITHM_MRF_CRF_444 = 1, } MF_VIDEO_PROCESSOR_ALGORITHM_TYPE; +typedef enum MFTOPOLOGY_DXVA_MODE +{ + MFTOPOLOGY_DXVA_DEFAULT = 0, + MFTOPOLOGY_DXVA_NONE = 1, + MFTOPOLOGY_DXVA_FULL = 2, +} MFTOPOLOGY_DXVA_MODE; + [ object, uuid(2eb1e945-18b8-4139-9b1a-d5d584818530), -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/5464
From: Rémi Bernon <rbernon(a)codeweavers.com> --- dlls/mf/tests/mf.c | 501 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 501 insertions(+) diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index fece60d37a7..86076a158a0 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -271,6 +271,315 @@ static void init_sink_node(IMFStreamSink *stream_sink, MF_CONNECT_METHOD method, } } +struct test_transform +{ + IMFTransform IMFTransform_iface; + LONG refcount; + + IMFAttributes *attributes; + + UINT input_count; + IMFMediaType **input_types; + IMFMediaType *input_type; + + UINT output_count; + IMFMediaType **output_types; + IMFMediaType *output_type; +}; + +static struct test_transform *test_transform_from_IMFTransform(IMFTransform *iface) +{ + return CONTAINING_RECORD(iface, struct test_transform, IMFTransform_iface); +} + +static HRESULT WINAPI test_transform_QueryInterface(IMFTransform *iface, REFIID iid, void **out) +{ + struct test_transform *transform = test_transform_from_IMFTransform(iface); + + if (IsEqualGUID(iid, &IID_IUnknown) + || IsEqualGUID(iid, &IID_IMFTransform)) + { + IMFTransform_AddRef(&transform->IMFTransform_iface); + *out = &transform->IMFTransform_iface; + return S_OK; + } + + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI test_transform_AddRef(IMFTransform *iface) +{ + struct test_transform *transform = test_transform_from_IMFTransform(iface); + ULONG refcount = InterlockedIncrement(&transform->refcount); + return refcount; +} + +static ULONG WINAPI test_transform_Release(IMFTransform *iface) +{ + struct test_transform *transform = test_transform_from_IMFTransform(iface); + ULONG refcount = InterlockedDecrement(&transform->refcount); + + if (!refcount) + { + if (transform->input_type) + IMFMediaType_Release(transform->input_type); + if (transform->output_type) + IMFMediaType_Release(transform->output_type); + if (transform->attributes) + IMFAttributes_Release(transform->attributes); + free(transform); + } + + return refcount; +} + +static HRESULT WINAPI test_transform_GetStreamLimits(IMFTransform *iface, DWORD *input_minimum, + DWORD *input_maximum, DWORD *output_minimum, DWORD *output_maximum) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_transform_GetStreamCount(IMFTransform *iface, DWORD *inputs, DWORD *outputs) +{ + *inputs = *outputs = 1; + return S_OK; +} + +static HRESULT WINAPI test_transform_GetStreamIDs(IMFTransform *iface, DWORD input_size, DWORD *inputs, + DWORD output_size, DWORD *outputs) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI test_transform_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info) +{ + ok(0, "Unexpected %s call.\n", __func__); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_transform_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info) +{ + ok(0, "Unexpected %s call.\n", __func__); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_transform_GetAttributes(IMFTransform *iface, IMFAttributes **attributes) +{ + struct test_transform *transform = test_transform_from_IMFTransform(iface); + if (!(*attributes = transform->attributes)) + return E_NOTIMPL; + IMFAttributes_AddRef(*attributes); + return S_OK; +} + +static HRESULT WINAPI test_transform_GetInputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI test_transform_GetOutputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI test_transform_DeleteInputStream(IMFTransform *iface, DWORD id) +{ + ok(0, "Unexpected %s call.\n", __func__); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_transform_AddInputStreams(IMFTransform *iface, DWORD streams, DWORD *ids) +{ + ok(0, "Unexpected %s call.\n", __func__); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_transform_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index, + IMFMediaType **type) +{ + struct test_transform *transform = test_transform_from_IMFTransform(iface); + + if (index >= transform->input_count) + { + *type = NULL; + return MF_E_NO_MORE_TYPES; + } + + *type = transform->input_types[index]; + IMFMediaType_AddRef(*type); + return S_OK; +} + +static HRESULT WINAPI test_transform_GetOutputAvailableType(IMFTransform *iface, DWORD id, + DWORD index, IMFMediaType **type) +{ + struct test_transform *transform = test_transform_from_IMFTransform(iface); + + if (index >= transform->output_count) + { + *type = NULL; + return MF_E_NO_MORE_TYPES; + } + + *type = transform->output_types[index]; + IMFMediaType_AddRef(*type); + return S_OK; +} + +static HRESULT WINAPI test_transform_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) +{ + struct test_transform *transform = test_transform_from_IMFTransform(iface); + if (flags & MFT_SET_TYPE_TEST_ONLY) + { + todo_wine ok(0, "Unexpected %s call.\n", __func__); + return winetest_platform_is_wine ? S_OK : E_NOTIMPL; + } + if (transform->input_type) + IMFMediaType_Release(transform->input_type); + if ((transform->input_type = type)) + IMFMediaType_AddRef(transform->input_type); + return S_OK; +} + +static HRESULT WINAPI test_transform_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) +{ + struct test_transform *transform = test_transform_from_IMFTransform(iface); + if (flags & MFT_SET_TYPE_TEST_ONLY) + { + todo_wine ok(0, "Unexpected %s call.\n", __func__); + return winetest_platform_is_wine ? S_OK : E_NOTIMPL; + } + if (transform->output_type) + IMFMediaType_Release(transform->output_type); + if ((transform->output_type = type)) + IMFMediaType_AddRef(transform->output_type); + return S_OK; +} + +static HRESULT WINAPI test_transform_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) +{ + struct test_transform *transform = test_transform_from_IMFTransform(iface); + if (!(*type = transform->input_type)) + return MF_E_TRANSFORM_TYPE_NOT_SET; + IMFMediaType_AddRef(*type); + return S_OK; +} + +static HRESULT WINAPI test_transform_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) +{ + struct test_transform *transform = test_transform_from_IMFTransform(iface); + if (!(*type = transform->output_type)) + return MF_E_TRANSFORM_TYPE_NOT_SET; + IMFMediaType_AddRef(*type); + return S_OK; +} + +static HRESULT WINAPI test_transform_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *flags) +{ + ok(0, "Unexpected %s call.\n", __func__); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_transform_GetOutputStatus(IMFTransform *iface, DWORD *flags) +{ + ok(0, "Unexpected %s call.\n", __func__); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_transform_SetOutputBounds(IMFTransform *iface, LONGLONG lower, LONGLONG upper) +{ + ok(0, "Unexpected %s call.\n", __func__); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_transform_ProcessEvent(IMFTransform *iface, DWORD id, IMFMediaEvent *event) +{ + ok(0, "Unexpected %s call.\n", __func__); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) +{ + ok(0, "Unexpected %s call.\n", __func__); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_transform_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) +{ + ok(0, "Unexpected %s call.\n", __func__); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_transform_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, + MFT_OUTPUT_DATA_BUFFER *data, DWORD *status) +{ + ok(0, "Unexpected %s call.\n", __func__); + return E_NOTIMPL; +} + +static const IMFTransformVtbl test_transform_vtbl = +{ + test_transform_QueryInterface, + test_transform_AddRef, + test_transform_Release, + test_transform_GetStreamLimits, + test_transform_GetStreamCount, + test_transform_GetStreamIDs, + test_transform_GetInputStreamInfo, + test_transform_GetOutputStreamInfo, + test_transform_GetAttributes, + test_transform_GetInputStreamAttributes, + test_transform_GetOutputStreamAttributes, + test_transform_DeleteInputStream, + test_transform_AddInputStreams, + test_transform_GetInputAvailableType, + test_transform_GetOutputAvailableType, + test_transform_SetInputType, + test_transform_SetOutputType, + test_transform_GetInputCurrentType, + test_transform_GetOutputCurrentType, + test_transform_GetInputStatus, + test_transform_GetOutputStatus, + test_transform_SetOutputBounds, + test_transform_ProcessEvent, + test_transform_ProcessMessage, + test_transform_ProcessInput, + test_transform_ProcessOutput, +}; + +static HRESULT WINAPI test_transform_create(UINT input_count, IMFMediaType **input_types, + UINT output_count, IMFMediaType **output_types, BOOL d3d_aware, IMFTransform **out) +{ + struct test_transform *transform; + HRESULT hr; + + if (!(transform = calloc(1, sizeof(*transform)))) + return E_OUTOFMEMORY; + transform->IMFTransform_iface.lpVtbl = &test_transform_vtbl; + transform->refcount = 1; + + transform->input_count = input_count; + transform->input_types = input_types; + transform->input_type = input_types[0]; + IMFMediaType_AddRef(transform->input_type); + transform->output_count = output_count; + transform->output_types = output_types; + transform->output_type = output_types[0]; + IMFMediaType_AddRef(transform->output_type); + + hr = MFCreateAttributes(&transform->attributes, 1); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFAttributes_SetUINT32(transform->attributes, &MF_SA_D3D_AWARE, d3d_aware); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFAttributes_SetUINT32(transform->attributes, &MF_SA_D3D11_AWARE, d3d_aware); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + *out = &transform->IMFTransform_iface; + return S_OK; +} + DEFINE_EXPECT(test_source_BeginGetEvent); DEFINE_EXPECT(test_source_QueueEvent); DEFINE_EXPECT(test_source_Start); @@ -1730,6 +2039,8 @@ struct test_stream_sink IMFStreamSink IMFStreamSink_iface; IMFMediaTypeHandler *handler; IMFMediaSink *media_sink; + + IMFAttributes *attributes; }; static struct test_stream_sink *impl_from_IMFStreamSink(IMFStreamSink *iface) @@ -1739,6 +2050,8 @@ static struct test_stream_sink *impl_from_IMFStreamSink(IMFStreamSink *iface) static HRESULT WINAPI test_stream_sink_QueryInterface(IMFStreamSink *iface, REFIID riid, void **obj) { + struct test_stream_sink *impl = impl_from_IMFStreamSink(iface); + if (IsEqualIID(riid, &IID_IMFStreamSink) || IsEqualIID(riid, &IID_IMFMediaEventGenerator) || IsEqualIID(riid, &IID_IUnknown)) @@ -1747,6 +2060,12 @@ static HRESULT WINAPI test_stream_sink_QueryInterface(IMFStreamSink *iface, REFI return S_OK; } + if (IsEqualIID(riid, &IID_IMFAttributes) && impl->attributes) + { + IMFAttributes_AddRef((*obj = impl->attributes)); + return S_OK; + } + *obj = NULL; return E_NOINTERFACE; } @@ -4582,6 +4901,187 @@ static void test_topology_loader_evr(void) CoUninitialize(); } +static void test_topology_loader_d3d_init(IMFTopology *topology, IMFMediaSource *source, IMFPresentationDescriptor *pd, IMFStreamDescriptor *sd, + UINT transform_count, IMFTransform **transforms, IMFStreamSink *sink) +{ + IMFTopologyNode *prev_node, *node; + HRESULT hr; + UINT i; + + hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &node); + ok(hr == S_OK, "got hr %#lx.\n", hr); + init_source_node(source, MF_CONNECT_DIRECT, node, pd, sd); + hr = IMFTopology_AddNode(topology, node); + ok(hr == S_OK, "got hr %#lx.\n", hr); + prev_node = node; + + for (i = 0; i < transform_count; i++) + { + hr = MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &node); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFTopologyNode_SetObject(node, (IUnknown *)transforms[i]); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFTopology_AddNode(topology, node); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFTopologyNode_ConnectOutput(prev_node, 0, node, 0); + ok(hr == S_OK, "Failed to connect nodes, hr %#lx.\n", hr); + IMFTopologyNode_Release(prev_node); + prev_node = node; + } + + hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &node); + ok(hr == S_OK, "got hr %#lx.\n", hr); + init_sink_node(sink, MF_CONNECT_DIRECT, node); + hr = IMFTopology_AddNode(topology, node); + ok(hr == S_OK, "got hr %#lx.\n", hr); + hr = IMFTopologyNode_ConnectOutput(prev_node, 0, node, 0); + ok(hr == S_OK, "Failed to connect nodes, hr %#lx.\n", hr); + IMFTopologyNode_Release(prev_node); + IMFTopologyNode_Release(node); +} + +static void test_topology_loader_d3d(void) +{ + static const media_type_desc video_media_type_desc = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32), + ATTR_RATIO(MF_MT_FRAME_SIZE, 1280, 720), + }; + + struct test_stream_sink stream_sink = test_stream_sink; + struct test_handler handler = test_handler; + IMFTopology *topology, *full_topology; + IMFPresentationDescriptor *pd; + IMFTransform *transforms[4]; + IMFMediaType *media_type; + IMFStreamDescriptor *sd; + IMFMediaSource *source; + IMFTopoLoader *loader; + HRESULT hr; + WORD count; + LONG ref; + + hr = MFCreateMediaType(&media_type); + ok(hr == S_OK, "got hr %#lx.\n", hr); + init_media_type(media_type, video_media_type_desc, -1); + + stream_sink.handler = &handler.IMFMediaTypeHandler_iface; + hr = MFCreateAttributes(&stream_sink.attributes, 1); + ok(hr == S_OK, "got hr %#lx.\n", hr); + + handler.media_types_count = 1; + handler.media_types = &media_type; + + hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); + ok(hr == S_OK, "got hr %#lx.\n", hr); + + hr = MFCreateTopoLoader(&loader); + ok(hr == S_OK, "got hr %#lx.\n", hr); + hr = MFCreateTopology(&topology); + ok(hr == S_OK, "got hr %#lx.\n", hr); + + create_descriptors(1, &media_type, &video_media_type_desc, &pd, &sd); + source = create_test_source(pd); + + test_topology_loader_d3d_init(topology, source, pd, sd, 0, NULL, &stream_sink.IMFStreamSink_iface); + + hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL); + ok(hr == S_OK, "got hr %#lx.\n", hr); + ref = IMFTopology_GetNodeCount(full_topology, &count); + ok(hr == S_OK, "got hr %#lx.\n", hr); + ok(count == 2, "got count %u.\n", count); + ref = IMFTopology_Release(full_topology); + ok(ref == 0, "Release returned %ld\n", ref); + + + /* sink D3D aware attribute doesn't change the resolved topology */ + + hr = IMFAttributes_SetUINT32(stream_sink.attributes, &MF_SA_D3D11_AWARE, 1); + ok(hr == S_OK, "got hr %#lx.\n", hr); + hr = IMFAttributes_SetUINT32(stream_sink.attributes, &MF_SA_D3D_AWARE, 1); + ok(hr == S_OK, "got hr %#lx.\n", hr); + + hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL); + 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); + ref = IMFTopology_Release(full_topology); + ok(ref == 0, "Release returned %ld\n", ref); + + + /* source D3D aware attribute doesn't change the resolved topology */ + + hr = IMFStreamDescriptor_SetUINT32(sd, &MF_SA_D3D11_AWARE, 1); + ok(hr == S_OK, "got hr %#lx.\n", hr); + hr = IMFStreamDescriptor_SetUINT32(sd, &MF_SA_D3D_AWARE, 1); + ok(hr == S_OK, "got hr %#lx.\n", hr); + + hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL); + 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); + ref = IMFTopology_Release(full_topology); + ok(ref == 0, "Release returned %ld\n", ref); + + ref = IMFTopology_Release(topology); + ok(ref == 0, "Release returned %ld\n", ref); + ref = IMFTopoLoader_Release(loader); + ok(ref == 0, "Release returned %ld\n", ref); + + + /* transform D3D aware attribute doesn't change the resolved topology */ + + hr = MFCreateTopoLoader(&loader); + ok(hr == S_OK, "got hr %#lx.\n", hr); + hr = MFCreateTopology(&topology); + ok(hr == S_OK, "got hr %#lx.\n", hr); + + test_transform_create(1, &media_type, 1, &media_type, FALSE, &transforms[0]); + test_transform_create(1, &media_type, 1, &media_type, TRUE, &transforms[1]); + test_transform_create(1, &media_type, 1, &media_type, FALSE, &transforms[2]); + test_transform_create(1, &media_type, 1, &media_type, TRUE, &transforms[3]); + + test_topology_loader_d3d_init(topology, source, pd, sd, 4, transforms, &stream_sink.IMFStreamSink_iface); + + IMFTransform_Release(transforms[0]); + IMFTransform_Release(transforms[1]); + IMFTransform_Release(transforms[2]); + IMFTransform_Release(transforms[3]); + + hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL); + 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); + ref = IMFTopology_Release(full_topology); + ok(ref == 0, "Release returned %ld\n", ref); + + ref = IMFTopology_Release(topology); + ok(ref == 0, "Release returned %ld\n", ref); + ref = IMFTopoLoader_Release(loader); + ok(ref == 0, "Release returned %ld\n", ref); + + + ref = IMFMediaSource_Release(source); + ok(ref == 0, "Release returned %ld\n", ref); + ref = IMFPresentationDescriptor_Release(pd); + ok(ref == 0, "Release returned %ld\n", ref); + ref = IMFStreamDescriptor_Release(sd); + ok(ref == 0, "Release returned %ld\n", ref); + + hr = MFShutdown(); + ok(hr == S_OK, "Shutdown failure, hr %#lx.\n", hr); + + + IMFAttributes_Release(stream_sink.attributes); + IMFMediaType_Release(media_type); + + winetest_pop_context(); +} + static HRESULT WINAPI testshutdown_QueryInterface(IMFShutdown *iface, REFIID riid, void **obj) { if (IsEqualIID(riid, &IID_IMFShutdown) || @@ -8254,6 +8754,7 @@ START_TEST(mf) test_topology_tee_node(); test_topology_loader(); test_topology_loader_evr(); + test_topology_loader_d3d(); test_MFGetService(); test_sequencer_source(); test_media_session(); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/5464
From: Rémi Bernon <rbernon(a)codeweavers.com> --- dlls/mf/tests/Makefile.in | 2 +- dlls/mf/tests/mf.c | 604 +++++++++++++++++++++++++++++++++++++- 2 files changed, 600 insertions(+), 6 deletions(-) diff --git a/dlls/mf/tests/Makefile.in b/dlls/mf/tests/Makefile.in index 3bb0c66de0a..cdd5e4a6af8 100644 --- a/dlls/mf/tests/Makefile.in +++ b/dlls/mf/tests/Makefile.in @@ -1,5 +1,5 @@ TESTDLL = mf.dll -IMPORTS = mf mfplat dmoguids mfuuid strmiids uuid wmcodecdspuuid ole32 user32 propsys msdmo d3d11 msvfw32 +IMPORTS = mf mfplat dmoguids mfuuid strmiids uuid wmcodecdspuuid ole32 user32 propsys msdmo d3d9 d3d11 dxva2 msvfw32 SOURCES = \ mf.c \ diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 86076a158a0..fd37b9520d5 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -34,6 +34,7 @@ #include "uuids.h" #include "wmcodecdsp.h" #include "nserror.h" +#include "d3d11_4.h" #include "mf_test.h" @@ -137,6 +138,27 @@ static HWND create_window(void) 0, 0, r.right - r.left, r.bottom - r.top, NULL, NULL, NULL, NULL); } +static IDirect3DDevice9 *create_d3d9_device(IDirect3D9 *d3d9, HWND focus_window) +{ + D3DPRESENT_PARAMETERS present_parameters = {0}; + IDirect3DDevice9 *device = NULL; + + present_parameters.BackBufferWidth = 640; + present_parameters.BackBufferHeight = 480; + present_parameters.BackBufferFormat = D3DFMT_X8R8G8B8; + present_parameters.SwapEffect = D3DSWAPEFFECT_DISCARD; + present_parameters.hDeviceWindow = focus_window; + present_parameters.Windowed = TRUE; + present_parameters.EnableAutoDepthStencil = TRUE; + present_parameters.AutoDepthStencilFormat = D3DFMT_D24S8; + present_parameters.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER; + + IDirect3D9_CreateDevice(d3d9, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, focus_window, + D3DCREATE_HARDWARE_VERTEXPROCESSING, &present_parameters, &device); + + return device; +} + static IMFSample *create_sample(const BYTE *data, ULONG size) { IMFMediaBuffer *media_buffer; @@ -277,6 +299,7 @@ struct test_transform LONG refcount; IMFAttributes *attributes; + const MFT_OUTPUT_STREAM_INFO *output_stream_info; UINT input_count; IMFMediaType **input_types; @@ -285,6 +308,11 @@ struct test_transform UINT output_count; IMFMediaType **output_types; IMFMediaType *output_type; + + IDirect3DDeviceManager9 *expect_d3d9_device_manager; + BOOL got_d3d9_device_manager; + IMFDXGIDeviceManager *expect_dxgi_device_manager; + BOOL got_dxgi_device_manager; }; static struct test_transform *test_transform_from_IMFTransform(IMFTransform *iface) @@ -359,10 +387,22 @@ static HRESULT WINAPI test_transform_GetInputStreamInfo(IMFTransform *iface, DWO return E_NOTIMPL; } +static void test_transform_set_output_stream_info(IMFTransform *iface, const MFT_OUTPUT_STREAM_INFO *info) +{ + struct test_transform *transform = test_transform_from_IMFTransform(iface); + transform->output_stream_info = info; +} + static HRESULT WINAPI test_transform_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info) { - ok(0, "Unexpected %s call.\n", __func__); - return E_NOTIMPL; + struct test_transform *transform = test_transform_from_IMFTransform(iface); + + ok(!!transform->output_stream_info, "Unexpected %s iface %p call.\n", __func__, iface); + if (!transform->output_stream_info) + return E_NOTIMPL; + + *info = *transform->output_stream_info; + return S_OK; } static HRESULT WINAPI test_transform_GetAttributes(IMFTransform *iface, IMFAttributes **attributes) @@ -500,10 +540,75 @@ static HRESULT WINAPI test_transform_ProcessEvent(IMFTransform *iface, DWORD id, return E_NOTIMPL; } +static void test_transform_set_expect_d3d9_device_manager(IMFTransform *iface, IDirect3DDeviceManager9 *manager) +{ + struct test_transform *transform = test_transform_from_IMFTransform(iface); + transform->expect_d3d9_device_manager = manager; +} + +static void test_transform_set_expect_dxgi_device_manager(IMFTransform *iface, IMFDXGIDeviceManager *manager) +{ + struct test_transform *transform = test_transform_from_IMFTransform(iface); + transform->expect_dxgi_device_manager = manager; +} + static HRESULT WINAPI test_transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) { - ok(0, "Unexpected %s call.\n", __func__); - return E_NOTIMPL; + struct test_transform *transform = test_transform_from_IMFTransform(iface); + switch (message) + { + case MFT_MESSAGE_SET_D3D_MANAGER: + ok(!!param, "Unexpected param.\n"); + ok(transform->expect_d3d9_device_manager || transform->expect_dxgi_device_manager, "Unexpected %s call.\n", __func__); + + if (transform->expect_d3d9_device_manager) + { + IDirect3DDeviceManager9 *manager; + HRESULT hr; + + check_interface((IUnknown *)param, &IID_IMFDXGIDeviceManager, FALSE); + hr = IUnknown_QueryInterface((IUnknown *)param, &IID_IDirect3DDeviceManager9, (void **)&manager); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(manager == transform->expect_d3d9_device_manager, "got manager %p\n", manager); + IDirect3DDeviceManager9_Release(manager); + + transform->got_d3d9_device_manager = TRUE; + } + if (transform->expect_dxgi_device_manager) + { + IMFDXGIDeviceManager *manager; + HRESULT hr; + + check_interface((IUnknown *)param, &IID_IDirect3DDeviceManager9, FALSE); + hr = IUnknown_QueryInterface((IUnknown *)param, &IID_IMFDXGIDeviceManager, (void **)&manager); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(manager == transform->expect_dxgi_device_manager, "got manager %p\n", manager); + if (manager) IMFDXGIDeviceManager_Release(manager); + + transform->got_dxgi_device_manager = TRUE; + } + return S_OK; + + default: + ok(0, "Unexpected %s call.\n", __func__); + return E_NOTIMPL; + } +} + +static BOOL test_transform_got_d3d9_device_manager(IMFTransform *iface) +{ + struct test_transform *transform = test_transform_from_IMFTransform(iface); + BOOL ret = transform->got_d3d9_device_manager; + transform->got_d3d9_device_manager = FALSE; + return ret; +} + +static BOOL test_transform_got_dxgi_device_manager(IMFTransform *iface) +{ + struct test_transform *transform = test_transform_from_IMFTransform(iface); + BOOL ret = transform->got_dxgi_device_manager; + transform->got_dxgi_device_manager = FALSE; + return ret; } static HRESULT WINAPI test_transform_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) @@ -2037,10 +2142,12 @@ static const struct test_media_sink test_media_sink = {.IMFMediaSink_iface.lpVtb struct test_stream_sink { IMFStreamSink IMFStreamSink_iface; + IMFGetService IMFGetService_iface; IMFMediaTypeHandler *handler; IMFMediaSink *media_sink; IMFAttributes *attributes; + IUnknown *device_manager; }; static struct test_stream_sink *impl_from_IMFStreamSink(IMFStreamSink *iface) @@ -2066,6 +2173,13 @@ static HRESULT WINAPI test_stream_sink_QueryInterface(IMFStreamSink *iface, REFI return S_OK; } + if (IsEqualIID(riid, &IID_IMFGetService)) + { + *obj = &impl->IMFGetService_iface; + IMFGetService_AddRef(&impl->IMFGetService_iface); + return S_OK; + } + *obj = NULL; return E_NOINTERFACE; } @@ -2177,7 +2291,52 @@ static const IMFStreamSinkVtbl test_stream_sink_vtbl = test_stream_sink_Flush, }; -static const struct test_stream_sink test_stream_sink = {.IMFStreamSink_iface.lpVtbl = &test_stream_sink_vtbl}; +static struct test_stream_sink *impl_from_IMFGetService(IMFGetService *iface) +{ + return CONTAINING_RECORD(iface, struct test_stream_sink, IMFGetService_iface); +} + +static HRESULT WINAPI test_stream_sink_get_service_QueryInterface(IMFGetService *iface, REFIID riid, void **obj) +{ + struct test_stream_sink *stream = impl_from_IMFGetService(iface); + return IMFStreamSink_QueryInterface(&stream->IMFStreamSink_iface, riid, obj); +} + +static ULONG WINAPI test_stream_sink_get_service_AddRef(IMFGetService *iface) +{ + struct test_stream_sink *stream = impl_from_IMFGetService(iface); + return IMFStreamSink_AddRef(&stream->IMFStreamSink_iface); +} + +static ULONG WINAPI test_stream_sink_get_service_Release(IMFGetService *iface) +{ + struct test_stream_sink *stream = impl_from_IMFGetService(iface); + return IMFStreamSink_Release(&stream->IMFStreamSink_iface); +} + +static HRESULT WINAPI test_stream_sink_get_service_GetService(IMFGetService *iface, REFGUID service, REFIID riid, void **obj) +{ + struct test_stream_sink *stream = impl_from_IMFGetService(iface); + + if (IsEqualGUID(service, &MR_VIDEO_ACCELERATION_SERVICE) && stream->device_manager) + return IUnknown_QueryInterface(stream->device_manager, riid, obj); + + return E_NOINTERFACE; +} + +static const IMFGetServiceVtbl test_stream_sink_get_service_vtbl = +{ + test_stream_sink_get_service_QueryInterface, + test_stream_sink_get_service_AddRef, + test_stream_sink_get_service_Release, + test_stream_sink_get_service_GetService, +}; + +static const struct test_stream_sink test_stream_sink = +{ + .IMFStreamSink_iface.lpVtbl = &test_stream_sink_vtbl, + .IMFGetService_iface.lpVtbl = &test_stream_sink_get_service_vtbl, +}; struct test_callback { @@ -5082,6 +5241,435 @@ static void test_topology_loader_d3d(void) winetest_pop_context(); } +static void test_topology_loader_d3d9(MFTOPOLOGY_DXVA_MODE mode) +{ + static const media_type_desc video_media_type_desc = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32), + ATTR_RATIO(MF_MT_FRAME_SIZE, 1280, 720), + }; + + struct test_stream_sink stream_sink = test_stream_sink; + MFT_OUTPUT_STREAM_INFO output_stream_info = {0}; + struct test_handler handler = test_handler; + IMFTopology *topology, *full_topology; + IDirect3DDeviceManager9 *d3d9_manager; + IMFPresentationDescriptor *pd; + IDirect3DDevice9 *d3d9_device; + IMFTransform *transforms[4]; + IMFMediaType *media_type; + IMFStreamDescriptor *sd; + IMFMediaSource *source; + IMFTopoLoader *loader; + IDirect3D9 *d3d9; + UINT token; + HRESULT hr; + WORD count; + HWND hwnd; + BOOL ret; + LONG ref; + + winetest_push_context("d3d9 mode %d", mode); + + hwnd = create_window(); + + if (!(d3d9 = Direct3DCreate9(D3D_SDK_VERSION))) + { + skip("Failed to create a D3D9 object, skipping tests.\n"); + goto skip_d3d9; + } + if (!(d3d9_device = create_d3d9_device(d3d9, hwnd))) + { + skip("Failed to create a D3D9 device, skipping tests.\n"); + IDirect3D9_Release(d3d9); + goto skip_d3d9; + } + IDirect3D9_Release(d3d9); + + hr = DXVA2CreateDirect3DDeviceManager9(&token, &d3d9_manager); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IDirect3DDeviceManager9_ResetDevice(d3d9_manager, d3d9_device, token); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IDirect3DDevice9_Release(d3d9_device); + + hr = MFCreateMediaType(&media_type); + ok(hr == S_OK, "got hr %#lx.\n", hr); + init_media_type(media_type, video_media_type_desc, -1); + + stream_sink.handler = &handler.IMFMediaTypeHandler_iface; + hr = MFCreateAttributes(&stream_sink.attributes, 1); + ok(hr == S_OK, "got hr %#lx.\n", hr); + hr = IMFAttributes_SetUINT32(stream_sink.attributes, &MF_SA_D3D_AWARE, 1); + ok(hr == S_OK, "got hr %#lx.\n", hr); + + stream_sink.device_manager = (IUnknown *)d3d9_manager; + + handler.media_types_count = 1; + handler.media_types = &media_type; + + hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); + ok(hr == S_OK, "got hr %#lx.\n", hr); + + + hr = MFCreateTopoLoader(&loader); + ok(hr == S_OK, "got hr %#lx.\n", hr); + hr = MFCreateTopology(&topology); + ok(hr == S_OK, "got hr %#lx.\n", hr); + hr = IMFTopology_SetUINT32(topology, &MF_TOPOLOGY_DXVA_MODE, mode); + ok(hr == S_OK, "got hr %#lx.\n", hr); + + create_descriptors(1, &media_type, &video_media_type_desc, &pd, &sd); + hr = IMFStreamDescriptor_SetUINT32(sd, &MF_SA_D3D_AWARE, 1); + ok(hr == S_OK, "got hr %#lx.\n", hr); + source = create_test_source(pd); + + + /* D3D aware transforms connected to downstream non-D3D-aware transforms don't receive a device manager */ + + test_transform_create(1, &media_type, 1, &media_type, FALSE, &transforms[0]); + test_transform_create(1, &media_type, 1, &media_type, TRUE, &transforms[1]); + test_transform_create(1, &media_type, 1, &media_type, FALSE, &transforms[2]); + test_transform_create(1, &media_type, 1, &media_type, TRUE, &transforms[3]); + + test_topology_loader_d3d_init(topology, source, pd, sd, 4, transforms, &stream_sink.IMFStreamSink_iface); + + IMFMediaSource_Release(source); + IMFPresentationDescriptor_Release(pd); + IMFStreamDescriptor_Release(sd); + + test_transform_set_output_stream_info(transforms[3], &output_stream_info); + + if (mode == MFTOPOLOGY_DXVA_FULL) + { + test_transform_set_expect_d3d9_device_manager(transforms[1], d3d9_manager); + test_transform_set_expect_d3d9_device_manager(transforms[3], d3d9_manager); + } + + hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL); + 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); + ref = IMFTopology_Release(full_topology); + ok(ref == 0, "Release returned %ld\n", ref); + + if (mode == MFTOPOLOGY_DXVA_FULL) + { + ret = test_transform_got_d3d9_device_manager(transforms[0]); + ok(!ret, "got d3d9 device manager\n"); + ret = test_transform_got_d3d9_device_manager(transforms[1]); + ok(!ret, "got d3d9 device manager\n"); + 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"); + } + + /* copier is inserted before the sink if preceding node may allocate samples without a device manager */ + + output_stream_info.dwFlags = MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES; + hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL); + ok(hr == S_OK, "got hr %#lx.\n", hr); + 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); + else + ok(count == 7, "got count %u.\n", count); + ref = IMFTopology_Release(full_topology); + ok(ref == 0, "Release returned %ld\n", ref); + + if (mode == MFTOPOLOGY_DXVA_FULL) + { + ret = test_transform_got_d3d9_device_manager(transforms[0]); + ok(!ret, "got d3d9 device manager\n"); + ret = test_transform_got_d3d9_device_manager(transforms[1]); + ok(!ret, "got d3d9 device manager\n"); + 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"); + } + + output_stream_info.dwFlags = MFT_OUTPUT_STREAM_PROVIDES_SAMPLES; + hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL); + ok(hr == S_OK, "got hr %#lx.\n", hr); + 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); + else + ok(count == 7, "got count %u.\n", count); + ref = IMFTopology_Release(full_topology); + ok(ref == 0, "Release returned %ld\n", ref); + + if (mode == MFTOPOLOGY_DXVA_FULL) + { + ret = test_transform_got_d3d9_device_manager(transforms[0]); + ok(!ret, "got d3d9 device manager\n"); + ret = test_transform_got_d3d9_device_manager(transforms[1]); + ok(!ret, "got d3d9 device manager\n"); + 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"); + } + + winetest_pop_context(); + + ref = IMFTopology_Release(topology); + ok(ref == 0, "Release returned %ld\n", ref); + ref = IMFTopoLoader_Release(loader); + ok(ref == 0, "Release returned %ld\n", ref); + + IMFTransform_Release(transforms[0]); + IMFTransform_Release(transforms[1]); + IMFTransform_Release(transforms[2]); + IMFTransform_Release(transforms[3]); + + + IMFAttributes_Release(stream_sink.attributes); + IMFMediaType_Release(media_type); + + hr = MFShutdown(); + ok(hr == S_OK, "Shutdown failure, hr %#lx.\n", hr); + + IDirect3DDeviceManager9_Release(d3d9_manager); + +skip_d3d9: + DestroyWindow(hwnd); + + winetest_pop_context(); +} + +static void test_topology_loader_d3d11(MFTOPOLOGY_DXVA_MODE mode) +{ + static const media_type_desc video_media_type_desc = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32), + ATTR_RATIO(MF_MT_FRAME_SIZE, 1280, 720), + }; + + struct test_stream_sink stream_sink = test_stream_sink; + MFT_OUTPUT_STREAM_INFO output_stream_info = {0}; + struct test_handler handler = test_handler; + IMFTopology *topology, *full_topology; + IMFDXGIDeviceManager *dxgi_manager; + ID3D11Multithread *multithread; + IMFPresentationDescriptor *pd; + IMFTransform *transforms[4]; + IMFMediaType *media_type; + IMFStreamDescriptor *sd; + IMFMediaSource *source; + IMFTopoLoader *loader; + ID3D11Device *d3d11; + UINT token; + HRESULT hr; + WORD count; + BOOL ret; + LONG ref; + + winetest_push_context("d3d11 mode %d", mode); + + hr = D3D11CreateDevice(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, D3D11_CREATE_DEVICE_VIDEO_SUPPORT, NULL, 0, + D3D11_SDK_VERSION, &d3d11, NULL, NULL); + if (FAILED(hr)) + { + skip("D3D11 device creation failed, skipping tests.\n"); + goto skip_d3d11; + } + + hr = ID3D11Device_QueryInterface(d3d11, &IID_ID3D11Multithread, (void **)&multithread); + ok(hr == S_OK, "got %#lx\n", hr); + ID3D11Multithread_SetMultithreadProtected(multithread, TRUE); + ID3D11Multithread_Release(multithread); + + hr = pMFCreateDXGIDeviceManager(&token, &dxgi_manager); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IMFDXGIDeviceManager_ResetDevice(dxgi_manager, (IUnknown *)d3d11, token); + ok(hr == S_OK, "got %#lx\n", hr); + ID3D11Device_Release(d3d11); + + + hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); + ok(hr == S_OK, "got hr %#lx.\n", hr); + + hr = MFCreateMediaType(&media_type); + ok(hr == S_OK, "got hr %#lx.\n", hr); + init_media_type(media_type, video_media_type_desc, -1); + + stream_sink.handler = &handler.IMFMediaTypeHandler_iface; + hr = MFCreateAttributes(&stream_sink.attributes, 1); + ok(hr == S_OK, "got hr %#lx.\n", hr); + hr = IMFAttributes_SetUINT32(stream_sink.attributes, &MF_SA_D3D11_AWARE, 1); + ok(hr == S_OK, "got hr %#lx.\n", hr); + stream_sink.device_manager = (IUnknown *)dxgi_manager; + + handler.media_types_count = 1; + handler.media_types = &media_type; + + create_descriptors(1, &media_type, &video_media_type_desc, &pd, &sd); + hr = IMFStreamDescriptor_SetUINT32(sd, &MF_SA_D3D11_AWARE, 1); + ok(hr == S_OK, "got hr %#lx.\n", hr); + source = create_test_source(pd); + + + /* D3D aware transforms connected to downstream non-D3D-aware transforms don't receive a device manager */ + + hr = MFCreateTopoLoader(&loader); + ok(hr == S_OK, "got hr %#lx.\n", hr); + hr = MFCreateTopology(&topology); + ok(hr == S_OK, "got hr %#lx.\n", hr); + hr = IMFTopology_SetUINT32(topology, &MF_TOPOLOGY_DXVA_MODE, mode); + ok(hr == S_OK, "got hr %#lx.\n", hr); + + test_transform_create(1, &media_type, 1, &media_type, TRUE, &transforms[0]); + test_transform_create(1, &media_type, 1, &media_type, TRUE, &transforms[1]); + test_transform_create(1, &media_type, 1, &media_type, FALSE, &transforms[2]); + test_transform_create(1, &media_type, 1, &media_type, FALSE, &transforms[3]); + + test_topology_loader_d3d_init(topology, source, pd, sd, 4, transforms, &stream_sink.IMFStreamSink_iface); + + test_transform_set_output_stream_info(transforms[3], &output_stream_info); + + if (mode == MFTOPOLOGY_DXVA_FULL) + { + test_transform_set_expect_dxgi_device_manager(transforms[2], dxgi_manager); + test_transform_set_expect_dxgi_device_manager(transforms[3], dxgi_manager); + } + + hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL); + ok(hr == S_OK, "got hr %#lx.\n", hr); + ref = IMFTopology_GetNodeCount(full_topology, &count); + ok(hr == S_OK, "got hr %#lx.\n", hr); + ok(count == 6, "got count %u.\n", count); + ref = IMFTopology_Release(full_topology); + ok(ref == 0, "Release returned %ld\n", ref); + + if (mode == MFTOPOLOGY_DXVA_FULL) + { + ret = test_transform_got_dxgi_device_manager(transforms[0]); + ok(!ret, "got dxgi device manager\n"); + 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]); + ok(!ret, "got dxgi device manager\n"); + ret = test_transform_got_dxgi_device_manager(transforms[3]); + ok(!ret, "got dxgi device manager\n"); + } + + /* copier is never needed in MFTOPOLOGY_DXVA_NONE mode */ + + output_stream_info.dwFlags = MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES; + hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL); + ok(hr == S_OK, "got hr %#lx.\n", hr); + ref = IMFTopology_GetNodeCount(full_topology, &count); + ok(hr == S_OK, "got hr %#lx.\n", hr); + if (mode == MFTOPOLOGY_DXVA_NONE) + ok(count == 6, "got count %u.\n", count); + else + todo_wine ok(count == 7, "got count %u.\n", count); + ref = IMFTopology_Release(full_topology); + ok(ref == 0, "Release returned %ld\n", ref); + + if (mode == MFTOPOLOGY_DXVA_FULL) + { + ret = test_transform_got_dxgi_device_manager(transforms[0]); + ok(!ret, "got dxgi device manager\n"); + 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]); + ok(!ret, "got dxgi device manager\n"); + ret = test_transform_got_dxgi_device_manager(transforms[3]); + ok(!ret, "got dxgi device manager\n"); + } + + output_stream_info.dwFlags = 0; + + ref = IMFTopology_Release(topology); + ok(ref == 0, "Release returned %ld\n", ref); + ref = IMFTopoLoader_Release(loader); + ok(ref == 0, "Release returned %ld\n", ref); + + IMFTransform_Release(transforms[0]); + IMFTransform_Release(transforms[1]); + IMFTransform_Release(transforms[2]); + IMFTransform_Release(transforms[3]); + + + /* D3D aware transforms connected together to downstream D3D-aware sink receive a device manager */ + + hr = MFCreateTopoLoader(&loader); + ok(hr == S_OK, "got hr %#lx.\n", hr); + hr = MFCreateTopology(&topology); + ok(hr == S_OK, "got hr %#lx.\n", hr); + hr = IMFTopology_SetUINT32(topology, &MF_TOPOLOGY_DXVA_MODE, mode); + ok(hr == S_OK, "got hr %#lx.\n", hr); + + test_transform_create(1, &media_type, 1, &media_type, FALSE, &transforms[0]); + test_transform_create(1, &media_type, 1, &media_type, FALSE, &transforms[1]); + test_transform_create(1, &media_type, 1, &media_type, TRUE, &transforms[2]); + test_transform_create(1, &media_type, 1, &media_type, TRUE, &transforms[3]); + + test_topology_loader_d3d_init(topology, source, pd, sd, 4, transforms, &stream_sink.IMFStreamSink_iface); + + test_transform_set_output_stream_info(transforms[3], &output_stream_info); + + if (mode == MFTOPOLOGY_DXVA_FULL) + { + test_transform_set_expect_dxgi_device_manager(transforms[2], dxgi_manager); + test_transform_set_expect_dxgi_device_manager(transforms[3], dxgi_manager); + } + + hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL); + ok(hr == S_OK, "got hr %#lx.\n", hr); + ref = IMFTopology_GetNodeCount(full_topology, &count); + ok(hr == S_OK, "got hr %#lx.\n", hr); + ok(count == 6, "got count %u.\n", count); + ref = IMFTopology_Release(full_topology); + ok(ref == 0, "Release returned %ld\n", ref); + + if (mode == MFTOPOLOGY_DXVA_FULL) + { + ret = test_transform_got_dxgi_device_manager(transforms[0]); + ok(!ret, "got dxgi device manager\n"); + 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"); + ret = test_transform_got_dxgi_device_manager(transforms[3]); + todo_wine ok(!!ret, "got dxgi device manager\n"); + } + + ref = IMFTopology_Release(topology); + ok(ref == 0, "Release returned %ld\n", ref); + ref = IMFTopoLoader_Release(loader); + ok(ref == 0, "Release returned %ld\n", ref); + + IMFTransform_Release(transforms[0]); + IMFTransform_Release(transforms[1]); + IMFTransform_Release(transforms[2]); + IMFTransform_Release(transforms[3]); + + + IMFMediaSource_Release(source); + IMFPresentationDescriptor_Release(pd); + IMFStreamDescriptor_Release(sd); + + IMFAttributes_Release(stream_sink.attributes); + IMFMediaType_Release(media_type); + + hr = MFShutdown(); + ok(hr == S_OK, "Shutdown failure, hr %#lx.\n", hr); + + IMFDXGIDeviceManager_Release(dxgi_manager); + +skip_d3d11: + winetest_pop_context(); +} + static HRESULT WINAPI testshutdown_QueryInterface(IMFShutdown *iface, REFIID riid, void **obj) { if (IsEqualIID(riid, &IID_IMFShutdown) || @@ -8755,6 +9343,12 @@ START_TEST(mf) test_topology_loader(); test_topology_loader_evr(); test_topology_loader_d3d(); + test_topology_loader_d3d9(MFTOPOLOGY_DXVA_DEFAULT); + test_topology_loader_d3d9(MFTOPOLOGY_DXVA_NONE); + test_topology_loader_d3d9(MFTOPOLOGY_DXVA_FULL); + test_topology_loader_d3d11(MFTOPOLOGY_DXVA_DEFAULT); + test_topology_loader_d3d11(MFTOPOLOGY_DXVA_NONE); + test_topology_loader_d3d11(MFTOPOLOGY_DXVA_FULL); test_MFGetService(); test_sequencer_source(); test_media_session(); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/5464
Added more tests with a sink device manager, showing cases where sample copier is supposed to be inserted. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/5464#note_67268
This is not great. Do we need to this platform check? I think it's fine to implement TEST_ONLY even if only wine uses it. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/5464#note_67269
Is this one needed? -- https://gitlab.winehq.org/wine/wine/-/merge_requests/5464#note_67270
This seems fine. Something to think about, maybe we'll split tests in more files, at this rate it grows quickly with number of stubs required. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/5464#note_67271
On Tue Apr 9 09:24:59 2024 +0000, Nikolay Sivov wrote:
This seems fine. Something to think about, maybe we'll split tests in more files, at this rate it grows quickly with number of stubs required. Yeah, I considered moving the mock components into dedicated files but I'm not very sure how to do it. I don't think winetest infrastructure let us have .c files without dedicated tests, so maybe something like `test_transform.h`, etc..., that could make them more easily copied and reused to other modules.
Or maybe split the topology tests. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/5464#note_67317
participants (2)
-
Nikolay Sivov (@nsivov) -
Rémi Bernon