[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