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 { - return video_desc->Format == D3DFMT_A8R8G8B8 || - video_desc->Format == D3DFMT_X8R8G8B8 || - video_desc->Format == D3DFMT_YUY2; + const GUID *guid; + const D3DFORMAT *input_formats; +}; + +static const D3DFORMAT software_processor_input_formats[] = +{ + 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))) {