[PATCH] dxva2: Introduce progressive processor device.

Nikolay Sivov nsivov at codeweavers.com
Tue Nov 23 06:21:45 CST 2021


The point is to provide a device, with similar caps and NV12 support,
while keeping software device on its own, the way it should be.

This is based on research by Derek Lesho.

Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/dxva2/main.c        | 126 +++++++++++++++++++++++++++------
 dlls/dxva2/tests/dxva2.c | 149 +++++++++++++++++++++++++++++++++++++++
 dlls/evr/mixer.c         |   2 +
 3 files changed, 257 insertions(+), 20 deletions(-)

diff --git a/dlls/dxva2/main.c b/dlls/dxva2/main.c
index 401b5cc976b..5beac4164a6 100644
--- a/dlls/dxva2/main.c
+++ b/dlls/dxva2/main.c
@@ -34,6 +34,8 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(dxva2);
 
+#define D3DFMT_NV12 MAKEFOURCC('N','V','1','2')
+
 enum device_handle_flags
 {
     HANDLE_FLAG_OPEN = 0x1,
@@ -125,6 +127,22 @@ static struct video_processor *impl_from_IDirectXVideoProcessor(IDirectXVideoPro
     return CONTAINING_RECORD(iface, struct video_processor, IDirectXVideoProcessor_iface);
 }
 
+static const DXVA2_VideoProcessorCaps software_processor_caps =
+{
+    .DeviceCaps = DXVA2_VPDev_SoftwareDevice,
+    .InputPool = D3DPOOL_SYSTEMMEM,
+    .VideoProcessorOperations = DXVA2_VideoProcess_PlanarAlpha | DXVA2_VideoProcess_YUV2RGB |
+            DXVA2_VideoProcess_StretchX | DXVA2_VideoProcess_StretchY | DXVA2_VideoProcess_SubRects |
+            DXVA2_VideoProcess_SubStreams | DXVA2_VideoProcess_SubStreamsExtended | DXVA2_VideoProcess_YUV2RGBExtended,
+};
+
+static const DXVA2_VideoProcessorCaps progressive_processor_caps =
+{
+    .DeviceCaps = DXVA2_VPDev_HardwareDevice,
+    .InputPool = D3DPOOL_DEFAULT,
+    .VideoProcessorOperations = DXVA2_VideoProcess_YUV2RGB | DXVA2_VideoProcess_StretchX | DXVA2_VideoProcess_StretchY,
+};
+
 static HRESULT WINAPI video_processor_QueryInterface(IDirectXVideoProcessor *iface, REFIID riid, void **obj)
 {
     if (IsEqualIID(riid, &IID_IDirectXVideoProcessor) ||
@@ -210,12 +228,11 @@ static HRESULT WINAPI video_processor_GetVideoProcessorCaps(IDirectXVideoProcess
 
     if (IsEqualGUID(&processor->device, &DXVA2_VideoProcSoftwareDevice))
     {
-        memset(caps, 0, sizeof(*caps));
-        caps->DeviceCaps = DXVA2_VPDev_SoftwareDevice;
-        caps->InputPool = D3DPOOL_SYSTEMMEM;
-        caps->VideoProcessorOperations = DXVA2_VideoProcess_PlanarAlpha | DXVA2_VideoProcess_YUV2RGB |
-                DXVA2_VideoProcess_StretchX | DXVA2_VideoProcess_StretchY | DXVA2_VideoProcess_SubRects |
-                DXVA2_VideoProcess_SubStreams | DXVA2_VideoProcess_SubStreamsExtended | DXVA2_VideoProcess_YUV2RGBExtended;
+        *caps = software_processor_caps;
+    }
+    else if (IsEqualGUID(&processor->device, &DXVA2_VideoProcProgressiveDevice))
+    {
+        *caps = progressive_processor_caps;
     }
     else
     {
@@ -419,28 +436,66 @@ static HRESULT WINAPI device_manager_processor_service_RegisterVideoProcessorSof
     return E_NOTIMPL;
 }
 
-static BOOL dxva_is_supported_stream_format(const DXVA2_VideoDesc *video_desc)
+struct dxva_processor_device_desc
+{
+    const GUID *guid;
+    const D3DFORMAT *input_formats;
+};
+
+static const D3DFORMAT software_processor_input_formats[] =
 {
-    return video_desc->Format == D3DFMT_A8R8G8B8 ||
-            video_desc->Format == D3DFMT_X8R8G8B8 ||
-            video_desc->Format == D3DFMT_YUY2;
+    D3DFMT_A8R8G8B8, D3DFMT_X8R8G8B8, D3DFMT_YUY2, 0
+};
+
+static const D3DFORMAT progressive_processor_input_formats[] =
+{
+    D3DFMT_A8R8G8B8, D3DFMT_X8R8G8B8, D3DFMT_YUY2, D3DFMT_NV12, 0
+};
+
+static const struct dxva_processor_device_desc processor_devices[] =
+{
+    { &DXVA2_VideoProcProgressiveDevice, progressive_processor_input_formats },
+    { &DXVA2_VideoProcSoftwareDevice, software_processor_input_formats },
+};
+
+static BOOL dxva_is_supported_stream_format(const DXVA2_VideoDesc *video_desc, const D3DFORMAT *formats)
+{
+    while (*formats)
+    {
+        if (*formats == video_desc->Format) return TRUE;
+        formats++;
+    }
+
+    return FALSE;
 }
 
 static HRESULT WINAPI device_manager_processor_service_GetVideoProcessorDeviceGuids(
         IDirectXVideoProcessorService *iface, const DXVA2_VideoDesc *video_desc, UINT *count, GUID **guids)
 {
+    unsigned int i;
+
     FIXME("%p, %p, %p, %p semi-stub.\n", iface, video_desc, count, guids);
 
     *count = 0;
 
-    if (!dxva_is_supported_stream_format(video_desc))
-        return E_FAIL;
-
-    if (!(*guids = CoTaskMemAlloc(sizeof(**guids))))
+    if (!(*guids = CoTaskMemAlloc(ARRAY_SIZE(processor_devices) * sizeof(**guids))))
         return E_OUTOFMEMORY;
 
-    memcpy(*guids, &DXVA2_VideoProcSoftwareDevice, sizeof(**guids));
-    *count = 1;
+    for (i = 0; i < ARRAY_SIZE(processor_devices); ++i)
+    {
+        if (dxva_is_supported_stream_format(video_desc, processor_devices[i].input_formats))
+        {
+            (*guids)[*count] = *processor_devices[i].guid;
+            *count += 1;
+        }
+    }
+
+    if (!*count)
+    {
+        CoTaskMemFree(*guids);
+        *guids = NULL;
+        return E_FAIL;
+    }
 
     return S_OK;
 }
@@ -453,7 +508,7 @@ static HRESULT WINAPI device_manager_processor_service_GetVideoProcessorRenderTa
 
     if (IsEqualGUID(deviceguid, &DXVA2_VideoProcSoftwareDevice))
     {
-        if (!dxva_is_supported_stream_format(video_desc))
+        if (!dxva_is_supported_stream_format(video_desc, software_processor_input_formats))
         {
             WARN("Unsupported content format %#x.\n", video_desc->Format);
             return E_FAIL;
@@ -468,6 +523,23 @@ static HRESULT WINAPI device_manager_processor_service_GetVideoProcessorRenderTa
 
         return S_OK;
     }
+    else if (IsEqualGUID(deviceguid, &DXVA2_VideoProcProgressiveDevice))
+    {
+        if (!dxva_is_supported_stream_format(video_desc, progressive_processor_input_formats))
+        {
+            WARN("Unsupported content format %#x.\n", video_desc->Format);
+            return E_FAIL;
+        }
+
+        if (!(*formats = CoTaskMemAlloc(2 * sizeof(**formats))))
+            return E_OUTOFMEMORY;
+
+        *count = 2;
+        (*formats)[0] = D3DFMT_X8R8G8B8;
+        (*formats)[1] = D3DFMT_NV12;
+
+        return S_OK;
+    }
     else
         FIXME("Unsupported device %s.\n", debugstr_guid(deviceguid));
 
@@ -484,12 +556,26 @@ static HRESULT WINAPI device_manager_processor_service_GetVideoProcessorSubStrea
 }
 
 static HRESULT WINAPI device_manager_processor_service_GetVideoProcessorCaps(
-        IDirectXVideoProcessorService *iface, REFGUID deviceguid, const DXVA2_VideoDesc *video_desc,
+        IDirectXVideoProcessorService *iface, REFGUID device, const DXVA2_VideoDesc *video_desc,
         D3DFORMAT rt_format, DXVA2_VideoProcessorCaps *caps)
 {
-    FIXME("%p, %s, %p, %u, %p.\n", iface, debugstr_guid(deviceguid), video_desc, rt_format, caps);
+    TRACE("%p, %s, %p, %u, %p.\n", iface, debugstr_guid(device), video_desc, rt_format, caps);
 
-    return E_NOTIMPL;
+    if (IsEqualGUID(device, &DXVA2_VideoProcSoftwareDevice))
+    {
+        *caps = software_processor_caps;
+    }
+    else if (IsEqualGUID(device, &DXVA2_VideoProcProgressiveDevice))
+    {
+        *caps = progressive_processor_caps;
+    }
+    else
+    {
+        FIXME("Unrecognized device %s.\n", debugstr_guid(device));
+        return E_NOTIMPL;
+    }
+
+    return S_OK;
 }
 
 static HRESULT WINAPI device_manager_processor_service_GetProcAmpRange(
diff --git a/dlls/dxva2/tests/dxva2.c b/dlls/dxva2/tests/dxva2.c
index e3307032ad4..01f8f568e6a 100644
--- a/dlls/dxva2/tests/dxva2.c
+++ b/dlls/dxva2/tests/dxva2.c
@@ -546,8 +546,157 @@ done:
     DestroyWindow(window);
 }
 
+static BOOL check_format_list(D3DFORMAT format, const D3DFORMAT *list, unsigned int count)
+{
+    unsigned int i;
+    for (i = 0; i < count; ++i)
+        if (list[i] == format) return TRUE;
+    return FALSE;
+}
+
+static void test_progressive_device(void)
+{
+    static const unsigned int processor_ops = DXVA2_VideoProcess_YUV2RGB |
+            DXVA2_VideoProcess_StretchX | DXVA2_VideoProcess_StretchY;
+    IDirectXVideoProcessorService *service;
+    IDirectXVideoProcessor *processor;
+    IDirect3DDeviceManager9 *manager;
+    D3DFORMAT format, *rt_formats;
+    DXVA2_VideoProcessorCaps caps;
+    DXVA2_VideoDesc video_desc;
+    IDirect3DDevice9 *device;
+    unsigned int count, i, j;
+    GUID guid, *guids;
+    IDirect3D9 *d3d;
+    HANDLE handle;
+    HWND window;
+    UINT token;
+    HRESULT hr;
+
+    static const D3DFORMAT input_formats[] =
+    {
+        D3DFMT_A8R8G8B8,
+        D3DFMT_X8R8G8B8,
+        D3DFMT_YUY2,
+        MAKEFOURCC('N','V','1','2'),
+    };
+
+    static const D3DFORMAT support_rt_formats[] =
+    {
+        D3DFMT_X8R8G8B8,
+        MAKEFOURCC('N','V','1','2'),
+        D3DFMT_YUY2,
+    };
+
+    window = create_window();
+    d3d = Direct3DCreate9(D3D_SDK_VERSION);
+    ok(!!d3d, "Failed to create a D3D object.\n");
+    if (!(device = create_device(d3d, window)))
+    {
+        skip("Failed to create a D3D device, skipping tests.\n");
+        goto done;
+    }
+
+    hr = DXVA2CreateDirect3DDeviceManager9(&token, &manager);
+    ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+    hr = IDirect3DDeviceManager9_ResetDevice(manager, device, token);
+    ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+    handle = NULL;
+    hr = IDirect3DDeviceManager9_OpenDeviceHandle(manager, &handle);
+    ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+    hr = IDirect3DDeviceManager9_GetVideoService(manager, handle, &IID_IDirectXVideoProcessorService,
+            (void **)&service);
+    ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+    memset(&video_desc, 0, sizeof(video_desc));
+    video_desc.SampleWidth = 64;
+    video_desc.SampleHeight = 64;
+    video_desc.Format = MAKEFOURCC('N','V','1','2');
+
+    hr = IDirectXVideoProcessorService_CreateVideoProcessor(service, &DXVA2_VideoProcProgressiveDevice, &video_desc,
+            D3DFMT_A8R8G8B8, 0, &processor);
+    if (FAILED(hr))
+    {
+        win_skip("VideoProcProgressiveDevice is not supported.\n");
+        goto unsupported;
+    }
+    IDirectXVideoProcessor_Release(processor);
+
+    for (i = 0; i < ARRAY_SIZE(input_formats); ++i)
+    {
+        init_video_desc(&video_desc, input_formats[i]);
+
+        /* Check that progressive device is returned for given input format. */
+        count = 0;
+        hr = IDirectXVideoProcessorService_GetVideoProcessorDeviceGuids(service, &video_desc, &count, &guids);
+        ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+        ok(count > 0, "Unexpected device count.\n");
+        for (j = 0; j < count; ++j)
+        {
+            if (IsEqualGUID(&guids[j], &DXVA2_VideoProcProgressiveDevice)) break;
+        }
+        ok(j < count, "Expected progressive device for format %#x.\n", input_formats[i]);
+        CoTaskMemFree(guids);
+
+        count = 0;
+        hr = IDirectXVideoProcessorService_GetVideoProcessorRenderTargets(service, &DXVA2_VideoProcProgressiveDevice,
+                &video_desc, &count, &rt_formats);
+        ok(hr == S_OK, "Unexpected hr %#x, format %d.\n", hr, input_formats[i]);
+        ok(count > 0, "Unexpected format count %u.\n", count);
+        for (j = 0; j < count; ++j)
+        {
+            ok(check_format_list(rt_formats[j], support_rt_formats, ARRAY_SIZE(support_rt_formats)),
+                    "Unexpected rt format %#x for input format %#x.\n", rt_formats[j], input_formats[i]);
+        }
+        CoTaskMemFree(rt_formats);
+    }
+
+    memset(&video_desc, 0, sizeof(video_desc));
+    video_desc.SampleWidth = 64;
+    video_desc.SampleHeight = 64;
+    video_desc.Format = MAKEFOURCC('N','V','1','2');
+
+    hr = IDirectXVideoProcessorService_CreateVideoProcessor(service, &DXVA2_VideoProcProgressiveDevice, &video_desc,
+            D3DFMT_A8R8G8B8, 0, &processor);
+    ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+    hr = IDirectXVideoProcessor_GetVideoProcessorCaps(processor, &caps);
+    ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+    ok(caps.DeviceCaps == DXVA2_VPDev_HardwareDevice, "Unexpected device type %#x.\n", caps.DeviceCaps);
+    ok(caps.InputPool == D3DPOOL_DEFAULT, "Unexpected input pool %#x.\n", caps.InputPool);
+    ok(!caps.NumForwardRefSamples, "Unexpected sample count.\n");
+    ok(!caps.NumBackwardRefSamples, "Unexpected sample count.\n");
+    ok(!caps.Reserved, "Unexpected field.\n");
+    ok((caps.VideoProcessorOperations & processor_ops) == processor_ops, "Unexpected processor operations %#x.\n",
+            caps.VideoProcessorOperations);
+
+    hr = IDirectXVideoProcessor_GetCreationParameters(processor, &guid, NULL, &format, NULL);
+    ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+    ok(IsEqualGUID(&guid, &DXVA2_VideoProcProgressiveDevice), "Unexpected device guid.\n");
+    ok(format == D3DFMT_A8R8G8B8, "Unexpected format %u.\n", format);
+
+    IDirectXVideoProcessor_Release(processor);
+
+unsupported:
+    IDirectXVideoProcessorService_Release(service);
+
+    hr = IDirect3DDeviceManager9_CloseDeviceHandle(manager, handle);
+    ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+    IDirect3DDevice9_Release(device);
+    IDirect3DDeviceManager9_Release(manager);
+
+done:
+    IDirect3D9_Release(d3d);
+    DestroyWindow(window);
+}
+
 START_TEST(dxva2)
 {
     test_device_manager();
     test_video_processor();
+    test_progressive_device();
 }
diff --git a/dlls/evr/mixer.c b/dlls/evr/mixer.c
index 8fe80c2f4a9..5af5b2861b3 100644
--- a/dlls/evr/mixer.c
+++ b/dlls/evr/mixer.c
@@ -956,6 +956,8 @@ static HRESULT WINAPI video_mixer_transform_SetOutputType(IMFTransform *iface, D
             if (SUCCEEDED(hr = IDirectXVideoProcessorService_CreateVideoProcessor(service, &mixer->output.rt_formats[i].device,
                     &video_desc, rt_format, MAX_MIXER_INPUT_SUBSTREAMS, &mixer->processor)))
             {
+                ERR("picked dxva device %s\n", debugstr_guid(&mixer->output.rt_formats[i].device));
+
                 if (FAILED(IMFMediaType_GetBlob(type, &MF_MT_GEOMETRIC_APERTURE, (UINT8 *)&mixer->aperture,
                         sizeof(mixer->aperture), NULL)))
                 {
-- 
2.33.0




More information about the wine-devel mailing list